mirror of
https://github.com/cloudflare/cloudflared.git
synced 2026-05-14 19:40:41 +00:00
TUN-8006: Update quic-go to latest upstream
This commit is contained in:
27
vendor/github.com/quic-go/qtls-go1-19/LICENSE
generated
vendored
27
vendor/github.com/quic-go/qtls-go1-19/LICENSE
generated
vendored
@@ -1,27 +0,0 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
6
vendor/github.com/quic-go/qtls-go1-19/README.md
generated
vendored
6
vendor/github.com/quic-go/qtls-go1-19/README.md
generated
vendored
@@ -1,6 +0,0 @@
|
||||
# qtls
|
||||
|
||||
[](https://pkg.go.dev/github.com/quic-go/qtls-go1-19)
|
||||
[](https://github.com/quic-go/qtls-go1-19/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).
|
||||
102
vendor/github.com/quic-go/qtls-go1-19/alert.go
generated
vendored
102
vendor/github.com/quic-go/qtls-go1-19/alert.go
generated
vendored
@@ -1,102 +0,0 @@
|
||||
// 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 qtls
|
||||
|
||||
import "strconv"
|
||||
|
||||
type alert uint8
|
||||
|
||||
// Alert is a TLS alert
|
||||
type Alert = alert
|
||||
|
||||
const (
|
||||
// alert level
|
||||
alertLevelWarning = 1
|
||||
alertLevelError = 2
|
||||
)
|
||||
|
||||
const (
|
||||
alertCloseNotify alert = 0
|
||||
alertUnexpectedMessage alert = 10
|
||||
alertBadRecordMAC alert = 20
|
||||
alertDecryptionFailed alert = 21
|
||||
alertRecordOverflow alert = 22
|
||||
alertDecompressionFailure alert = 30
|
||||
alertHandshakeFailure alert = 40
|
||||
alertBadCertificate alert = 42
|
||||
alertUnsupportedCertificate alert = 43
|
||||
alertCertificateRevoked alert = 44
|
||||
alertCertificateExpired alert = 45
|
||||
alertCertificateUnknown alert = 46
|
||||
alertIllegalParameter alert = 47
|
||||
alertUnknownCA alert = 48
|
||||
alertAccessDenied alert = 49
|
||||
alertDecodeError alert = 50
|
||||
alertDecryptError alert = 51
|
||||
alertExportRestriction alert = 60
|
||||
alertProtocolVersion alert = 70
|
||||
alertInsufficientSecurity alert = 71
|
||||
alertInternalError alert = 80
|
||||
alertInappropriateFallback alert = 86
|
||||
alertUserCanceled alert = 90
|
||||
alertNoRenegotiation alert = 100
|
||||
alertMissingExtension alert = 109
|
||||
alertUnsupportedExtension alert = 110
|
||||
alertCertificateUnobtainable alert = 111
|
||||
alertUnrecognizedName alert = 112
|
||||
alertBadCertificateStatusResponse alert = 113
|
||||
alertBadCertificateHashValue alert = 114
|
||||
alertUnknownPSKIdentity alert = 115
|
||||
alertCertificateRequired alert = 116
|
||||
alertNoApplicationProtocol alert = 120
|
||||
)
|
||||
|
||||
var alertText = map[alert]string{
|
||||
alertCloseNotify: "close notify",
|
||||
alertUnexpectedMessage: "unexpected message",
|
||||
alertBadRecordMAC: "bad record MAC",
|
||||
alertDecryptionFailed: "decryption failed",
|
||||
alertRecordOverflow: "record overflow",
|
||||
alertDecompressionFailure: "decompression failure",
|
||||
alertHandshakeFailure: "handshake failure",
|
||||
alertBadCertificate: "bad certificate",
|
||||
alertUnsupportedCertificate: "unsupported certificate",
|
||||
alertCertificateRevoked: "revoked certificate",
|
||||
alertCertificateExpired: "expired certificate",
|
||||
alertCertificateUnknown: "unknown certificate",
|
||||
alertIllegalParameter: "illegal parameter",
|
||||
alertUnknownCA: "unknown certificate authority",
|
||||
alertAccessDenied: "access denied",
|
||||
alertDecodeError: "error decoding message",
|
||||
alertDecryptError: "error decrypting message",
|
||||
alertExportRestriction: "export restriction",
|
||||
alertProtocolVersion: "protocol version not supported",
|
||||
alertInsufficientSecurity: "insufficient security level",
|
||||
alertInternalError: "internal error",
|
||||
alertInappropriateFallback: "inappropriate fallback",
|
||||
alertUserCanceled: "user canceled",
|
||||
alertNoRenegotiation: "no renegotiation",
|
||||
alertMissingExtension: "missing extension",
|
||||
alertUnsupportedExtension: "unsupported extension",
|
||||
alertCertificateUnobtainable: "certificate unobtainable",
|
||||
alertUnrecognizedName: "unrecognized name",
|
||||
alertBadCertificateStatusResponse: "bad certificate status response",
|
||||
alertBadCertificateHashValue: "bad certificate hash value",
|
||||
alertUnknownPSKIdentity: "unknown PSK identity",
|
||||
alertCertificateRequired: "certificate required",
|
||||
alertNoApplicationProtocol: "no application protocol",
|
||||
}
|
||||
|
||||
func (e alert) String() string {
|
||||
s, ok := alertText[e]
|
||||
if ok {
|
||||
return "tls: " + s
|
||||
}
|
||||
return "tls: alert(" + strconv.Itoa(int(e)) + ")"
|
||||
}
|
||||
|
||||
func (e alert) Error() string {
|
||||
return e.String()
|
||||
}
|
||||
293
vendor/github.com/quic-go/qtls-go1-19/auth.go
generated
vendored
293
vendor/github.com/quic-go/qtls-go1-19/auth.go
generated
vendored
@@ -1,293 +0,0 @@
|
||||
// Copyright 2017 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 qtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rsa"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
)
|
||||
|
||||
// verifyHandshakeSignature verifies a signature against pre-hashed
|
||||
// (if required) handshake contents.
|
||||
func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error {
|
||||
switch sigType {
|
||||
case signatureECDSA:
|
||||
pubKey, ok := pubkey.(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected an ECDSA public key, got %T", pubkey)
|
||||
}
|
||||
if !ecdsa.VerifyASN1(pubKey, signed, sig) {
|
||||
return errors.New("ECDSA verification failure")
|
||||
}
|
||||
case signatureEd25519:
|
||||
pubKey, ok := pubkey.(ed25519.PublicKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected an Ed25519 public key, got %T", pubkey)
|
||||
}
|
||||
if !ed25519.Verify(pubKey, signed, sig) {
|
||||
return errors.New("Ed25519 verification failure")
|
||||
}
|
||||
case signaturePKCS1v15:
|
||||
pubKey, ok := pubkey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected an RSA public key, got %T", pubkey)
|
||||
}
|
||||
if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, signed, sig); err != nil {
|
||||
return err
|
||||
}
|
||||
case signatureRSAPSS:
|
||||
pubKey, ok := pubkey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected an RSA public key, got %T", pubkey)
|
||||
}
|
||||
signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}
|
||||
if err := rsa.VerifyPSS(pubKey, hashFunc, signed, sig, signOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.New("internal error: unknown signature type")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
serverSignatureContext = "TLS 1.3, server CertificateVerify\x00"
|
||||
clientSignatureContext = "TLS 1.3, client CertificateVerify\x00"
|
||||
)
|
||||
|
||||
var signaturePadding = []byte{
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
}
|
||||
|
||||
// signedMessage returns the pre-hashed (if necessary) message to be signed by
|
||||
// certificate keys in TLS 1.3. See RFC 8446, Section 4.4.3.
|
||||
func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []byte {
|
||||
if sigHash == directSigning {
|
||||
b := &bytes.Buffer{}
|
||||
b.Write(signaturePadding)
|
||||
io.WriteString(b, context)
|
||||
b.Write(transcript.Sum(nil))
|
||||
return b.Bytes()
|
||||
}
|
||||
h := sigHash.New()
|
||||
h.Write(signaturePadding)
|
||||
io.WriteString(h, context)
|
||||
h.Write(transcript.Sum(nil))
|
||||
return h.Sum(nil)
|
||||
}
|
||||
|
||||
// typeAndHashFromSignatureScheme returns the corresponding signature type and
|
||||
// crypto.Hash for a given TLS SignatureScheme.
|
||||
func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) {
|
||||
switch signatureAlgorithm {
|
||||
case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
|
||||
sigType = signaturePKCS1v15
|
||||
case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
|
||||
sigType = signatureRSAPSS
|
||||
case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
|
||||
sigType = signatureECDSA
|
||||
case Ed25519:
|
||||
sigType = signatureEd25519
|
||||
default:
|
||||
return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
|
||||
}
|
||||
switch signatureAlgorithm {
|
||||
case PKCS1WithSHA1, ECDSAWithSHA1:
|
||||
hash = crypto.SHA1
|
||||
case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
|
||||
hash = crypto.SHA256
|
||||
case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
|
||||
hash = crypto.SHA384
|
||||
case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
|
||||
hash = crypto.SHA512
|
||||
case Ed25519:
|
||||
hash = directSigning
|
||||
default:
|
||||
return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
|
||||
}
|
||||
return sigType, hash, nil
|
||||
}
|
||||
|
||||
// legacyTypeAndHashFromPublicKey returns the fixed signature type and crypto.Hash for
|
||||
// a given public key used with TLS 1.0 and 1.1, before the introduction of
|
||||
// signature algorithm negotiation.
|
||||
func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash crypto.Hash, err error) {
|
||||
switch pub.(type) {
|
||||
case *rsa.PublicKey:
|
||||
return signaturePKCS1v15, crypto.MD5SHA1, nil
|
||||
case *ecdsa.PublicKey:
|
||||
return signatureECDSA, crypto.SHA1, nil
|
||||
case ed25519.PublicKey:
|
||||
// RFC 8422 specifies support for Ed25519 in TLS 1.0 and 1.1,
|
||||
// but it requires holding on to a handshake transcript to do a
|
||||
// full signature, and not even OpenSSL bothers with the
|
||||
// complexity, so we can't even test it properly.
|
||||
return 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2")
|
||||
default:
|
||||
return 0, 0, fmt.Errorf("tls: unsupported public key: %T", pub)
|
||||
}
|
||||
}
|
||||
|
||||
var rsaSignatureSchemes = []struct {
|
||||
scheme SignatureScheme
|
||||
minModulusBytes int
|
||||
maxVersion uint16
|
||||
}{
|
||||
// RSA-PSS is used with PSSSaltLengthEqualsHash, and requires
|
||||
// emLen >= hLen + sLen + 2
|
||||
{PSSWithSHA256, crypto.SHA256.Size()*2 + 2, VersionTLS13},
|
||||
{PSSWithSHA384, crypto.SHA384.Size()*2 + 2, VersionTLS13},
|
||||
{PSSWithSHA512, crypto.SHA512.Size()*2 + 2, VersionTLS13},
|
||||
// PKCS #1 v1.5 uses prefixes from hashPrefixes in crypto/rsa, and requires
|
||||
// emLen >= len(prefix) + hLen + 11
|
||||
// TLS 1.3 dropped support for PKCS #1 v1.5 in favor of RSA-PSS.
|
||||
{PKCS1WithSHA256, 19 + crypto.SHA256.Size() + 11, VersionTLS12},
|
||||
{PKCS1WithSHA384, 19 + crypto.SHA384.Size() + 11, VersionTLS12},
|
||||
{PKCS1WithSHA512, 19 + crypto.SHA512.Size() + 11, VersionTLS12},
|
||||
{PKCS1WithSHA1, 15 + crypto.SHA1.Size() + 11, VersionTLS12},
|
||||
}
|
||||
|
||||
// signatureSchemesForCertificate returns the list of supported SignatureSchemes
|
||||
// for a given certificate, based on the public key and the protocol version,
|
||||
// and optionally filtered by its explicit SupportedSignatureAlgorithms.
|
||||
//
|
||||
// This function must be kept in sync with supportedSignatureAlgorithms.
|
||||
// FIPS filtering is applied in the caller, selectSignatureScheme.
|
||||
func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
|
||||
priv, ok := cert.PrivateKey.(crypto.Signer)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var sigAlgs []SignatureScheme
|
||||
switch pub := priv.Public().(type) {
|
||||
case *ecdsa.PublicKey:
|
||||
if version != VersionTLS13 {
|
||||
// In TLS 1.2 and earlier, ECDSA algorithms are not
|
||||
// constrained to a single curve.
|
||||
sigAlgs = []SignatureScheme{
|
||||
ECDSAWithP256AndSHA256,
|
||||
ECDSAWithP384AndSHA384,
|
||||
ECDSAWithP521AndSHA512,
|
||||
ECDSAWithSHA1,
|
||||
}
|
||||
break
|
||||
}
|
||||
switch pub.Curve {
|
||||
case elliptic.P256():
|
||||
sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256}
|
||||
case elliptic.P384():
|
||||
sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384}
|
||||
case elliptic.P521():
|
||||
sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
case *rsa.PublicKey:
|
||||
size := pub.Size()
|
||||
sigAlgs = make([]SignatureScheme, 0, len(rsaSignatureSchemes))
|
||||
for _, candidate := range rsaSignatureSchemes {
|
||||
if size >= candidate.minModulusBytes && version <= candidate.maxVersion {
|
||||
sigAlgs = append(sigAlgs, candidate.scheme)
|
||||
}
|
||||
}
|
||||
case ed25519.PublicKey:
|
||||
sigAlgs = []SignatureScheme{Ed25519}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
if cert.SupportedSignatureAlgorithms != nil {
|
||||
var filteredSigAlgs []SignatureScheme
|
||||
for _, sigAlg := range sigAlgs {
|
||||
if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) {
|
||||
filteredSigAlgs = append(filteredSigAlgs, sigAlg)
|
||||
}
|
||||
}
|
||||
return filteredSigAlgs
|
||||
}
|
||||
return sigAlgs
|
||||
}
|
||||
|
||||
// selectSignatureScheme picks a SignatureScheme from the peer's preference list
|
||||
// that works with the selected certificate. It's only called for protocol
|
||||
// versions that support signature algorithms, so TLS 1.2 and 1.3.
|
||||
func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) {
|
||||
supportedAlgs := signatureSchemesForCertificate(vers, c)
|
||||
if len(supportedAlgs) == 0 {
|
||||
return 0, unsupportedCertificateError(c)
|
||||
}
|
||||
if len(peerAlgs) == 0 && vers == VersionTLS12 {
|
||||
// For TLS 1.2, if the client didn't send signature_algorithms then we
|
||||
// can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1.
|
||||
peerAlgs = []SignatureScheme{PKCS1WithSHA1, ECDSAWithSHA1}
|
||||
}
|
||||
// Pick signature scheme in the peer's preference order, as our
|
||||
// preference order is not configurable.
|
||||
for _, preferredAlg := range peerAlgs {
|
||||
if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, fipsSupportedSignatureAlgorithms) {
|
||||
continue
|
||||
}
|
||||
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
|
||||
return preferredAlg, nil
|
||||
}
|
||||
}
|
||||
return 0, errors.New("tls: peer doesn't support any of the certificate's signature algorithms")
|
||||
}
|
||||
|
||||
// unsupportedCertificateError returns a helpful error for certificates with
|
||||
// an unsupported private key.
|
||||
func unsupportedCertificateError(cert *Certificate) error {
|
||||
switch cert.PrivateKey.(type) {
|
||||
case rsa.PrivateKey, ecdsa.PrivateKey:
|
||||
return fmt.Errorf("tls: unsupported certificate: private key is %T, expected *%T",
|
||||
cert.PrivateKey, cert.PrivateKey)
|
||||
case *ed25519.PrivateKey:
|
||||
return fmt.Errorf("tls: unsupported certificate: private key is *ed25519.PrivateKey, expected ed25519.PrivateKey")
|
||||
}
|
||||
|
||||
signer, ok := cert.PrivateKey.(crypto.Signer)
|
||||
if !ok {
|
||||
return fmt.Errorf("tls: certificate private key (%T) does not implement crypto.Signer",
|
||||
cert.PrivateKey)
|
||||
}
|
||||
|
||||
switch pub := signer.Public().(type) {
|
||||
case *ecdsa.PublicKey:
|
||||
switch pub.Curve {
|
||||
case elliptic.P256():
|
||||
case elliptic.P384():
|
||||
case elliptic.P521():
|
||||
default:
|
||||
return fmt.Errorf("tls: unsupported certificate curve (%s)", pub.Curve.Params().Name)
|
||||
}
|
||||
case *rsa.PublicKey:
|
||||
return fmt.Errorf("tls: certificate RSA key size too small for supported signature algorithms")
|
||||
case ed25519.PublicKey:
|
||||
default:
|
||||
return fmt.Errorf("tls: unsupported certificate key (%T)", pub)
|
||||
}
|
||||
|
||||
if cert.SupportedSignatureAlgorithms != nil {
|
||||
return fmt.Errorf("tls: peer doesn't support the certificate custom signature algorithms")
|
||||
}
|
||||
|
||||
return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey)
|
||||
}
|
||||
693
vendor/github.com/quic-go/qtls-go1-19/cipher_suites.go
generated
vendored
693
vendor/github.com/quic-go/qtls-go1-19/cipher_suites.go
generated
vendored
@@ -1,693 +0,0 @@
|
||||
// Copyright 2010 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 qtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/hmac"
|
||||
"crypto/rc4"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"hash"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
// CipherSuite is a TLS cipher suite. Note that most functions in this package
|
||||
// accept and expose cipher suite IDs instead of this type.
|
||||
type CipherSuite struct {
|
||||
ID uint16
|
||||
Name string
|
||||
|
||||
// Supported versions is the list of TLS protocol versions that can
|
||||
// negotiate this cipher suite.
|
||||
SupportedVersions []uint16
|
||||
|
||||
// Insecure is true if the cipher suite has known security issues
|
||||
// due to its primitives, design, or implementation.
|
||||
Insecure bool
|
||||
}
|
||||
|
||||
var (
|
||||
supportedUpToTLS12 = []uint16{VersionTLS10, VersionTLS11, VersionTLS12}
|
||||
supportedOnlyTLS12 = []uint16{VersionTLS12}
|
||||
supportedOnlyTLS13 = []uint16{VersionTLS13}
|
||||
)
|
||||
|
||||
// CipherSuites returns a list of cipher suites currently implemented by this
|
||||
// package, excluding those with security issues, which are returned by
|
||||
// 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,
|
||||
// and might not match those returned by this function.
|
||||
func CipherSuites() []*CipherSuite {
|
||||
return []*CipherSuite{
|
||||
{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},
|
||||
{TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
|
||||
|
||||
{TLS_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", supportedOnlyTLS13, false},
|
||||
{TLS_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", supportedOnlyTLS13, false},
|
||||
{TLS_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", supportedOnlyTLS13, false},
|
||||
|
||||
{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_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},
|
||||
{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
|
||||
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
|
||||
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
|
||||
{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false},
|
||||
{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false},
|
||||
}
|
||||
}
|
||||
|
||||
// InsecureCipherSuites returns a list of cipher suites currently implemented by
|
||||
// this package and which have security issues.
|
||||
//
|
||||
// Most applications should not use the cipher suites in this list, and should
|
||||
// only use those returned by CipherSuites.
|
||||
func InsecureCipherSuites() []*CipherSuite {
|
||||
// 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},
|
||||
}
|
||||
}
|
||||
|
||||
// CipherSuiteName returns the standard name for the passed cipher suite ID
|
||||
// (e.g. "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), or a fallback representation
|
||||
// of the ID value if the cipher suite is not implemented by this package.
|
||||
func CipherSuiteName(id uint16) string {
|
||||
for _, c := range CipherSuites() {
|
||||
if c.ID == id {
|
||||
return c.Name
|
||||
}
|
||||
}
|
||||
for _, c := range InsecureCipherSuites() {
|
||||
if c.ID == id {
|
||||
return c.Name
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("0x%04X", id)
|
||||
}
|
||||
|
||||
const (
|
||||
// suiteECDHE indicates that the cipher suite involves elliptic curve
|
||||
// Diffie-Hellman. This means that it should only be selected when the
|
||||
// client indicates that it supports ECC with a curve and point format
|
||||
// that we're happy with.
|
||||
suiteECDHE = 1 << iota
|
||||
// suiteECSign indicates that the cipher suite involves an ECDSA or
|
||||
// EdDSA signature and therefore may only be selected when the server's
|
||||
// certificate is ECDSA or EdDSA. If this is not set then the cipher suite
|
||||
// is RSA based.
|
||||
suiteECSign
|
||||
// suiteTLS12 indicates that the cipher suite should only be advertised
|
||||
// and accepted when using TLS 1.2.
|
||||
suiteTLS12
|
||||
// suiteSHA384 indicates that the cipher suite uses SHA384 as the
|
||||
// handshake hash.
|
||||
suiteSHA384
|
||||
)
|
||||
|
||||
// A cipherSuite is a TLS 1.0–1.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.
|
||||
keyLen int
|
||||
macLen int
|
||||
ivLen int
|
||||
ka func(version uint16) keyAgreement
|
||||
// flags is a bitmask of the suite* values, above.
|
||||
flags int
|
||||
cipher func(key, iv []byte, isRead bool) any
|
||||
mac func(key []byte) hash.Hash
|
||||
aead func(key, fixedNonce []byte) aead
|
||||
}
|
||||
|
||||
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, 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, 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, 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},
|
||||
{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 TLS 1.0–1.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)
|
||||
if candidate == nil || !ok(candidate) {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, suppID := range supportedIDs {
|
||||
if id == suppID {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash
|
||||
// algorithm to be used with HKDF. See RFC 8446, Appendix B.4.
|
||||
type cipherSuiteTLS13 struct {
|
||||
id uint16
|
||||
keyLen int
|
||||
aead func(key, fixedNonce []byte) aead
|
||||
hash crypto.Hash
|
||||
}
|
||||
|
||||
type CipherSuiteTLS13 struct {
|
||||
ID uint16
|
||||
KeyLen int
|
||||
Hash crypto.Hash
|
||||
AEAD func(key, fixedNonce []byte) cipher.AEAD
|
||||
}
|
||||
|
||||
func (c *CipherSuiteTLS13) IVLen() int {
|
||||
return aeadNonceLength
|
||||
}
|
||||
|
||||
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.0–1.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 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) any {
|
||||
cipher, _ := rc4.NewCipher(key)
|
||||
return cipher
|
||||
}
|
||||
|
||||
func cipher3DES(key, iv []byte, isRead bool) any {
|
||||
block, _ := des.NewTripleDESCipher(key)
|
||||
if isRead {
|
||||
return cipher.NewCBCDecrypter(block, iv)
|
||||
}
|
||||
return cipher.NewCBCEncrypter(block, iv)
|
||||
}
|
||||
|
||||
func cipherAES(key, iv []byte, isRead bool) any {
|
||||
block, _ := aes.NewCipher(key)
|
||||
if isRead {
|
||||
return cipher.NewCBCDecrypter(block, iv)
|
||||
}
|
||||
return cipher.NewCBCEncrypter(block, iv)
|
||||
}
|
||||
|
||||
// macSHA1 returns a SHA-1 based constant time MAC.
|
||||
func macSHA1(key []byte) hash.Hash {
|
||||
h := sha1.New
|
||||
h = newConstantTimeHash(h)
|
||||
return hmac.New(h, key)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
cipher.AEAD
|
||||
|
||||
// explicitNonceLen returns the number of bytes of explicit nonce
|
||||
// included in each record. This is eight for older AEADs and
|
||||
// zero for modern ones.
|
||||
explicitNonceLen() int
|
||||
}
|
||||
|
||||
const (
|
||||
aeadNonceLength = 12
|
||||
noncePrefixLength = 4
|
||||
)
|
||||
|
||||
// prefixNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
|
||||
// each call.
|
||||
type prefixNonceAEAD struct {
|
||||
// nonce contains the fixed part of the nonce in the first four bytes.
|
||||
nonce [aeadNonceLength]byte
|
||||
aead cipher.AEAD
|
||||
}
|
||||
|
||||
func (f *prefixNonceAEAD) NonceSize() int { return aeadNonceLength - noncePrefixLength }
|
||||
func (f *prefixNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
||||
func (f *prefixNonceAEAD) explicitNonceLen() int { return f.NonceSize() }
|
||||
|
||||
func (f *prefixNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
||||
copy(f.nonce[4:], nonce)
|
||||
return f.aead.Seal(out, f.nonce[:], plaintext, additionalData)
|
||||
}
|
||||
|
||||
func (f *prefixNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
copy(f.nonce[4:], nonce)
|
||||
return f.aead.Open(out, f.nonce[:], ciphertext, additionalData)
|
||||
}
|
||||
|
||||
// xoredNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
|
||||
// before each call.
|
||||
type xorNonceAEAD struct {
|
||||
nonceMask [aeadNonceLength]byte
|
||||
aead cipher.AEAD
|
||||
}
|
||||
|
||||
func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
|
||||
func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
||||
func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
|
||||
|
||||
func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func aeadAESGCM(key, noncePrefix []byte) aead {
|
||||
if len(noncePrefix) != noncePrefixLength {
|
||||
panic("tls: internal error: wrong nonce length")
|
||||
}
|
||||
aes, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var aead cipher.AEAD
|
||||
aead, err = cipher.NewGCM(aes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ret := &prefixNonceAEAD{aead: aead}
|
||||
copy(ret.nonce[:], noncePrefix)
|
||||
return ret
|
||||
}
|
||||
|
||||
// AEADAESGCMTLS13 creates a new AES-GCM AEAD for TLS 1.3
|
||||
func AEADAESGCMTLS13(key, fixedNonce []byte) cipher.AEAD {
|
||||
return aeadAESGCMTLS13(key, fixedNonce)
|
||||
}
|
||||
|
||||
func aeadAESGCMTLS13(key, nonceMask []byte) aead {
|
||||
if len(nonceMask) != aeadNonceLength {
|
||||
panic("tls: internal error: wrong nonce length")
|
||||
}
|
||||
aes, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
aead, err := cipher.NewGCM(aes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ret := &xorNonceAEAD{aead: aead}
|
||||
copy(ret.nonceMask[:], nonceMask)
|
||||
return ret
|
||||
}
|
||||
|
||||
func aeadChaCha20Poly1305(key, nonceMask []byte) aead {
|
||||
if len(nonceMask) != aeadNonceLength {
|
||||
panic("tls: internal error: wrong nonce length")
|
||||
}
|
||||
aead, err := chacha20poly1305.New(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ret := &xorNonceAEAD{aead: aead}
|
||||
copy(ret.nonceMask[:], nonceMask)
|
||||
return ret
|
||||
}
|
||||
|
||||
type constantTimeHash interface {
|
||||
hash.Hash
|
||||
ConstantTimeSum(b []byte) []byte
|
||||
}
|
||||
|
||||
// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces
|
||||
// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC.
|
||||
type cthWrapper struct {
|
||||
h constantTimeHash
|
||||
}
|
||||
|
||||
func (c *cthWrapper) Size() int { return c.h.Size() }
|
||||
func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() }
|
||||
func (c *cthWrapper) Reset() { c.h.Reset() }
|
||||
func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
|
||||
func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) }
|
||||
|
||||
func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
|
||||
return func() hash.Hash {
|
||||
return &cthWrapper{h().(constantTimeHash)}
|
||||
}
|
||||
}
|
||||
|
||||
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
|
||||
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 {
|
||||
h.Write(extra)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func rsaKA(version uint16) keyAgreement {
|
||||
return rsaKeyAgreement{}
|
||||
}
|
||||
|
||||
func ecdheECDSAKA(version uint16) keyAgreement {
|
||||
return &ecdheKeyAgreement{
|
||||
isRSA: false,
|
||||
version: version,
|
||||
}
|
||||
}
|
||||
|
||||
func ecdheRSAKA(version uint16) keyAgreement {
|
||||
return &ecdheKeyAgreement{
|
||||
isRSA: true,
|
||||
version: version,
|
||||
}
|
||||
}
|
||||
|
||||
// mutualCipherSuite returns a cipherSuite given a list of supported
|
||||
// ciphersuites and the id requested by the peer.
|
||||
func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
|
||||
for _, id := range have {
|
||||
if id == want {
|
||||
return cipherSuiteByID(id)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cipherSuiteByID(id uint16) *cipherSuite {
|
||||
for _, cipherSuite := range cipherSuites {
|
||||
if cipherSuite.id == id {
|
||||
return cipherSuite
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mutualCipherSuiteTLS13(have []uint16, want uint16) *cipherSuiteTLS13 {
|
||||
for _, id := range have {
|
||||
if id == want {
|
||||
return cipherSuiteTLS13ByID(id)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13 {
|
||||
for _, cipherSuite := range cipherSuitesTLS13 {
|
||||
if cipherSuite.id == id {
|
||||
return cipherSuite
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A list of cipher suite IDs that are, or have been, implemented by this
|
||||
// package.
|
||||
//
|
||||
// See https://www.iana.org/assignments/tls-parameters/tls-parameters.xml
|
||||
const (
|
||||
// TLS 1.0 - 1.2 cipher suites.
|
||||
TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
|
||||
TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
|
||||
TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
|
||||
TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
|
||||
TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
|
||||
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a
|
||||
TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
|
||||
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
|
||||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
|
||||
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
|
||||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027
|
||||
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
|
||||
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
|
||||
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
|
||||
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca8
|
||||
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca9
|
||||
|
||||
// TLS 1.3 cipher suites.
|
||||
TLS_AES_128_GCM_SHA256 uint16 = 0x1301
|
||||
TLS_AES_256_GCM_SHA384 uint16 = 0x1302
|
||||
TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303
|
||||
|
||||
// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
|
||||
// that the client is doing version fallback. See RFC 7507.
|
||||
TLS_FALLBACK_SCSV uint16 = 0x5600
|
||||
|
||||
// Legacy names for the corresponding cipher suites with the correct _SHA256
|
||||
// suffix, retained for backward compatibility.
|
||||
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
|
||||
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
|
||||
)
|
||||
1513
vendor/github.com/quic-go/qtls-go1-19/common.go
generated
vendored
1513
vendor/github.com/quic-go/qtls-go1-19/common.go
generated
vendored
File diff suppressed because it is too large
Load Diff
1649
vendor/github.com/quic-go/qtls-go1-19/conn.go
generated
vendored
1649
vendor/github.com/quic-go/qtls-go1-19/conn.go
generated
vendored
File diff suppressed because it is too large
Load Diff
22
vendor/github.com/quic-go/qtls-go1-19/cpu.go
generated
vendored
22
vendor/github.com/quic-go/qtls-go1-19/cpu.go
generated
vendored
@@ -1,22 +0,0 @@
|
||||
//go:build !js
|
||||
// +build !js
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
12
vendor/github.com/quic-go/qtls-go1-19/cpu_other.go
generated
vendored
12
vendor/github.com/quic-go/qtls-go1-19/cpu_other.go
generated
vendored
@@ -1,12 +0,0 @@
|
||||
//go:build js
|
||||
// +build js
|
||||
|
||||
package qtls
|
||||
|
||||
var (
|
||||
hasGCMAsmAMD64 = false
|
||||
hasGCMAsmARM64 = false
|
||||
hasGCMAsmS390X = false
|
||||
|
||||
hasAESGCMHardwareSupport = false
|
||||
)
|
||||
1123
vendor/github.com/quic-go/qtls-go1-19/handshake_client.go
generated
vendored
1123
vendor/github.com/quic-go/qtls-go1-19/handshake_client.go
generated
vendored
File diff suppressed because it is too large
Load Diff
755
vendor/github.com/quic-go/qtls-go1-19/handshake_client_tls13.go
generated
vendored
755
vendor/github.com/quic-go/qtls-go1-19/handshake_client_tls13.go
generated
vendored
@@ -1,755 +0,0 @@
|
||||
// Copyright 2018 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 qtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
"crypto/rsa"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
)
|
||||
|
||||
type clientHandshakeStateTLS13 struct {
|
||||
c *Conn
|
||||
ctx context.Context
|
||||
serverHello *serverHelloMsg
|
||||
hello *clientHelloMsg
|
||||
ecdheParams ecdheParameters
|
||||
|
||||
session *clientSessionState
|
||||
earlySecret []byte
|
||||
binderKey []byte
|
||||
|
||||
certReq *certificateRequestMsgTLS13
|
||||
usingPSK bool
|
||||
sentDummyCCS bool
|
||||
suite *cipherSuiteTLS13
|
||||
transcript hash.Hash
|
||||
masterSecret []byte
|
||||
trafficSecret []byte // client_application_traffic_secret_0
|
||||
}
|
||||
|
||||
// handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheParams, and,
|
||||
// optionally, hs.session, hs.earlySecret and hs.binderKey to be set.
|
||||
func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||
c := hs.c
|
||||
|
||||
if needFIPS() {
|
||||
return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
|
||||
}
|
||||
|
||||
// The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
|
||||
// sections 4.1.2 and 4.1.3.
|
||||
if c.handshakes > 0 {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return errors.New("tls: server selected TLS 1.3 in a renegotiation")
|
||||
}
|
||||
|
||||
// Consistency check on the presence of a keyShare and its parameters.
|
||||
if hs.ecdheParams == nil || len(hs.hello.keyShares) != 1 {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
|
||||
if err := hs.checkServerHelloOrHRR(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hs.transcript = hs.suite.hash.New()
|
||||
|
||||
if err := transcriptMsg(hs.hello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
|
||||
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.processHelloRetryRequest(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.buffering = true
|
||||
if err := hs.processServerHello(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.updateConnectionState()
|
||||
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.establishHandshakeKeys(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.readServerParameters(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.readServerCertificate(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.updateConnectionState()
|
||||
if err := hs.readServerFinished(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendClientCertificate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendClientFinished(); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
atomic.StoreUint32(&c.handshakeStatus, 1)
|
||||
c.updateConnectionState()
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkServerHelloOrHRR does validity checks that apply to both ServerHello and
|
||||
// HelloRetryRequest messages. It sets hs.suite.
|
||||
func (hs *clientHandshakeStateTLS13) checkServerHelloOrHRR() error {
|
||||
c := hs.c
|
||||
|
||||
if hs.serverHello.supportedVersion == 0 {
|
||||
c.sendAlert(alertMissingExtension)
|
||||
return errors.New("tls: server selected TLS 1.3 using the legacy version field")
|
||||
}
|
||||
|
||||
if hs.serverHello.supportedVersion != VersionTLS13 {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server selected an invalid version after a HelloRetryRequest")
|
||||
}
|
||||
|
||||
if hs.serverHello.vers != VersionTLS12 {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server sent an incorrect legacy version")
|
||||
}
|
||||
|
||||
if hs.serverHello.ocspStapling ||
|
||||
hs.serverHello.ticketSupported ||
|
||||
hs.serverHello.secureRenegotiationSupported ||
|
||||
len(hs.serverHello.secureRenegotiation) != 0 ||
|
||||
len(hs.serverHello.alpnProtocol) != 0 ||
|
||||
len(hs.serverHello.scts) != 0 {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
return errors.New("tls: server sent a ServerHello extension forbidden in TLS 1.3")
|
||||
}
|
||||
|
||||
if !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server did not echo the legacy session ID")
|
||||
}
|
||||
|
||||
if hs.serverHello.compressionMethod != compressionNone {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server selected unsupported compression format")
|
||||
}
|
||||
|
||||
selectedSuite := mutualCipherSuiteTLS13(hs.hello.cipherSuites, hs.serverHello.cipherSuite)
|
||||
if hs.suite != nil && selectedSuite != hs.suite {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server changed cipher suite after a HelloRetryRequest")
|
||||
}
|
||||
if selectedSuite == nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server chose an unconfigured cipher suite")
|
||||
}
|
||||
hs.suite = selectedSuite
|
||||
c.cipherSuite = hs.suite.id
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
|
||||
// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
|
||||
func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
|
||||
if hs.sentDummyCCS {
|
||||
return nil
|
||||
}
|
||||
hs.sentDummyCCS = true
|
||||
|
||||
return hs.c.writeChangeCipherRecord()
|
||||
}
|
||||
|
||||
// processHelloRetryRequest handles the HRR in hs.serverHello, modifies and
|
||||
// resends hs.hello, and reads the new ServerHello into hs.serverHello.
|
||||
func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||
c := hs.c
|
||||
|
||||
// The first ClientHello gets double-hashed into the transcript upon a
|
||||
// HelloRetryRequest. (The idea is that the server might offload transcript
|
||||
// storage to the client in the cookie.) See RFC 8446, Section 4.4.1.
|
||||
chHash := hs.transcript.Sum(nil)
|
||||
hs.transcript.Reset()
|
||||
hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
||||
hs.transcript.Write(chHash)
|
||||
if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The only HelloRetryRequest extensions we support are key_share and
|
||||
// cookie, and clients must abort the handshake if the HRR would not result
|
||||
// in any change in the ClientHello.
|
||||
if hs.serverHello.selectedGroup == 0 && hs.serverHello.cookie == nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
|
||||
}
|
||||
|
||||
if hs.serverHello.cookie != nil {
|
||||
hs.hello.cookie = hs.serverHello.cookie
|
||||
}
|
||||
|
||||
if hs.serverHello.serverShare.group != 0 {
|
||||
c.sendAlert(alertDecodeError)
|
||||
return errors.New("tls: received malformed key_share extension")
|
||||
}
|
||||
|
||||
// If the server sent a key_share extension selecting a group, ensure it's
|
||||
// a group we advertised but did not send a key share for, and send a key
|
||||
// share for it this time.
|
||||
if curveID := hs.serverHello.selectedGroup; curveID != 0 {
|
||||
curveOK := false
|
||||
for _, id := range hs.hello.supportedCurves {
|
||||
if id == curveID {
|
||||
curveOK = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !curveOK {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server selected unsupported group")
|
||||
}
|
||||
if hs.ecdheParams.CurveID() == curveID {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
|
||||
}
|
||||
if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
|
||||
c.sendAlert(alertInternalError)
|
||||
return errors.New("tls: CurvePreferences includes unsupported curve")
|
||||
}
|
||||
params, err := generateECDHEParameters(c.config.rand(), curveID)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
hs.ecdheParams = params
|
||||
hs.hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
|
||||
}
|
||||
|
||||
hs.hello.raw = nil
|
||||
if len(hs.hello.pskIdentities) > 0 {
|
||||
pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
|
||||
if pskSuite == nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
if pskSuite.hash == hs.suite.hash {
|
||||
// Update binders and obfuscated_ticket_age.
|
||||
ticketAge := uint32(c.config.time().Sub(hs.session.receivedAt) / time.Millisecond)
|
||||
hs.hello.pskIdentities[0].obfuscatedTicketAge = ticketAge + hs.session.ageAdd
|
||||
|
||||
transcript := hs.suite.hash.New()
|
||||
transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
||||
transcript.Write(chHash)
|
||||
if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
helloBytes, err := hs.hello.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
transcript.Write(helloBytes)
|
||||
pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)}
|
||||
if err := hs.hello.updateBinders(pskBinders); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Server selected a cipher suite incompatible with the PSK.
|
||||
hs.hello.pskIdentities = nil
|
||||
hs.hello.pskBinders = nil
|
||||
}
|
||||
}
|
||||
|
||||
if hs.hello.earlyData && c.extraConfig != nil && c.extraConfig.Rejected0RTT != nil {
|
||||
c.extraConfig.Rejected0RTT()
|
||||
}
|
||||
hs.hello.earlyData = false // disable 0-RTT
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// serverHelloMsg is not included in the transcript
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverHello, ok := msg.(*serverHelloMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(serverHello, msg)
|
||||
}
|
||||
hs.serverHello = serverHello
|
||||
|
||||
if err := hs.checkServerHelloOrHRR(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *clientHandshakeStateTLS13) processServerHello() error {
|
||||
c := hs.c
|
||||
|
||||
if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return errors.New("tls: server sent two HelloRetryRequest messages")
|
||||
}
|
||||
|
||||
if len(hs.serverHello.cookie) != 0 {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
return errors.New("tls: server sent a cookie in a normal ServerHello")
|
||||
}
|
||||
|
||||
if hs.serverHello.selectedGroup != 0 {
|
||||
c.sendAlert(alertDecodeError)
|
||||
return errors.New("tls: malformed key_share extension")
|
||||
}
|
||||
|
||||
if hs.serverHello.serverShare.group == 0 {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server did not send a key share")
|
||||
}
|
||||
if hs.serverHello.serverShare.group != hs.ecdheParams.CurveID() {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server selected unsupported group")
|
||||
}
|
||||
|
||||
if !hs.serverHello.selectedIdentityPresent {
|
||||
return nil
|
||||
}
|
||||
|
||||
if int(hs.serverHello.selectedIdentity) >= len(hs.hello.pskIdentities) {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server selected an invalid PSK")
|
||||
}
|
||||
|
||||
if len(hs.hello.pskIdentities) != 1 || hs.session == nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
|
||||
if pskSuite == nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
if pskSuite.hash != hs.suite.hash {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: server selected an invalid PSK and cipher suite pair")
|
||||
}
|
||||
|
||||
hs.usingPSK = true
|
||||
c.didResume = true
|
||||
c.peerCertificates = hs.session.serverCertificates
|
||||
c.verifiedChains = hs.session.verifiedChains
|
||||
c.ocspResponse = hs.session.ocspResponse
|
||||
c.scts = hs.session.scts
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
|
||||
c := hs.c
|
||||
|
||||
sharedKey := hs.ecdheParams.SharedKey(hs.serverHello.serverShare.data)
|
||||
if sharedKey == nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: invalid server key share")
|
||||
}
|
||||
|
||||
earlySecret := hs.earlySecret
|
||||
if !hs.usingPSK {
|
||||
earlySecret = hs.suite.extract(nil, nil)
|
||||
}
|
||||
|
||||
handshakeSecret := hs.suite.extract(sharedKey,
|
||||
hs.suite.deriveSecret(earlySecret, "derived", nil))
|
||||
|
||||
clientSecret := hs.suite.deriveSecret(handshakeSecret,
|
||||
clientHandshakeTrafficLabel, hs.transcript)
|
||||
c.out.exportKey(EncryptionHandshake, hs.suite, clientSecret)
|
||||
c.out.setTrafficSecret(hs.suite, clientSecret)
|
||||
serverSecret := hs.suite.deriveSecret(handshakeSecret,
|
||||
serverHandshakeTrafficLabel, hs.transcript)
|
||||
c.in.exportKey(EncryptionHandshake, hs.suite, serverSecret)
|
||||
c.in.setTrafficSecret(hs.suite, serverSecret)
|
||||
|
||||
err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.hello.random, serverSecret)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
|
||||
hs.masterSecret = hs.suite.extract(nil,
|
||||
hs.suite.deriveSecret(handshakeSecret, "derived", nil))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *clientHandshakeStateTLS13) readServerParameters() error {
|
||||
c := hs.c
|
||||
|
||||
msg, err := c.readHandshake(hs.transcript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(encryptedExtensions, msg)
|
||||
}
|
||||
// Notify the caller if 0-RTT was rejected.
|
||||
if !encryptedExtensions.earlyData && hs.hello.earlyData && c.extraConfig != nil && c.extraConfig.Rejected0RTT != nil {
|
||||
c.extraConfig.Rejected0RTT()
|
||||
}
|
||||
c.used0RTT = encryptedExtensions.earlyData
|
||||
if hs.c.extraConfig != nil && hs.c.extraConfig.ReceivedExtensions != nil {
|
||||
hs.c.extraConfig.ReceivedExtensions(typeEncryptedExtensions, encryptedExtensions.additionalExtensions)
|
||||
}
|
||||
|
||||
if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
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")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
|
||||
c := hs.c
|
||||
|
||||
// Either a PSK or a certificate is always used, but not both.
|
||||
// See RFC 8446, Section 4.1.1.
|
||||
if hs.usingPSK {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
msg, err := c.readHandshake(hs.transcript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certReq, ok := msg.(*certificateRequestMsgTLS13)
|
||||
if ok {
|
||||
hs.certReq = certReq
|
||||
|
||||
msg, err = c.readHandshake(hs.transcript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
certMsg, ok := msg.(*certificateMsgTLS13)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
if len(certMsg.certificate.Certificate) == 0 {
|
||||
c.sendAlert(alertDecodeError)
|
||||
return errors.New("tls: received empty certificates message")
|
||||
}
|
||||
|
||||
c.scts = certMsg.certificate.SignedCertificateTimestamps
|
||||
c.ocspResponse = certMsg.certificate.OCSPStaple
|
||||
|
||||
if err := c.verifyServerCertificate(certMsg.certificate.Certificate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// certificateVerifyMsg is included in the transcript, but not until
|
||||
// after we verify the handshake signature, since the state before
|
||||
// this message was sent is used.
|
||||
msg, err = c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certVerify, ok := msg.(*certificateVerifyMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certVerify, msg)
|
||||
}
|
||||
|
||||
// See RFC 8446, Section 4.4.3.
|
||||
if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: certificate used with invalid signature algorithm")
|
||||
}
|
||||
sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: certificate used with invalid signature algorithm")
|
||||
}
|
||||
signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
|
||||
if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
|
||||
sigHash, signed, certVerify.signature); err != nil {
|
||||
c.sendAlert(alertDecryptError)
|
||||
return errors.New("tls: invalid signature by the server certificate: " + err.Error())
|
||||
}
|
||||
|
||||
if err := transcriptMsg(certVerify, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *clientHandshakeStateTLS13) readServerFinished() error {
|
||||
c := hs.c
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
finished, ok := msg.(*finishedMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(finished, msg)
|
||||
}
|
||||
|
||||
expectedMAC := hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
|
||||
if !hmac.Equal(expectedMAC, finished.verifyData) {
|
||||
c.sendAlert(alertDecryptError)
|
||||
return errors.New("tls: invalid server finished hash")
|
||||
}
|
||||
|
||||
if err := transcriptMsg(finished, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Derive secrets that take context through the server Finished.
|
||||
|
||||
hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
|
||||
clientApplicationTrafficLabel, hs.transcript)
|
||||
serverSecret := hs.suite.deriveSecret(hs.masterSecret,
|
||||
serverApplicationTrafficLabel, hs.transcript)
|
||||
c.in.exportKey(EncryptionApplication, hs.suite, serverSecret)
|
||||
c.in.setTrafficSecret(hs.suite, serverSecret)
|
||||
|
||||
err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.hello.random, serverSecret)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
|
||||
c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
|
||||
c := hs.c
|
||||
|
||||
if hs.certReq == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
certMsg := new(certificateMsgTLS13)
|
||||
|
||||
certMsg.certificate = *cert
|
||||
certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0
|
||||
certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we sent an empty certificate message, skip the CertificateVerify.
|
||||
if len(cert.Certificate) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
certVerifyMsg := new(certificateVerifyMsg)
|
||||
certVerifyMsg.hasSignatureAlgorithm = true
|
||||
|
||||
certVerifyMsg.signatureAlgorithm, err = selectSignatureScheme(c.vers, cert, hs.certReq.supportedSignatureAlgorithms)
|
||||
if err != nil {
|
||||
// getClientCertificate returned a certificate incompatible with the
|
||||
// CertificateRequestInfo supported signature algorithms.
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return err
|
||||
}
|
||||
|
||||
sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
|
||||
signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
|
||||
signOpts := crypto.SignerOpts(sigHash)
|
||||
if sigType == signatureRSAPSS {
|
||||
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
|
||||
}
|
||||
sig, err := cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return errors.New("tls: failed to sign handshake: " + err.Error())
|
||||
}
|
||||
certVerifyMsg.signature = sig
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
|
||||
c := hs.c
|
||||
|
||||
finished := &finishedMsg{
|
||||
verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
|
||||
}
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.out.exportKey(EncryptionApplication, hs.suite, hs.trafficSecret)
|
||||
c.out.setTrafficSecret(hs.suite, hs.trafficSecret)
|
||||
|
||||
if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil {
|
||||
c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
|
||||
resumptionLabel, hs.transcript)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
|
||||
if !c.isClient {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return errors.New("tls: received new session ticket from a client")
|
||||
}
|
||||
|
||||
if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// See RFC 8446, Section 4.6.1.
|
||||
if msg.lifetime == 0 {
|
||||
return nil
|
||||
}
|
||||
lifetime := time.Duration(msg.lifetime) * time.Second
|
||||
if lifetime > maxSessionTicketLifetime {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: received a session ticket with invalid lifetime")
|
||||
}
|
||||
|
||||
cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
|
||||
if cipherSuite == nil || c.resumptionSecret == nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
|
||||
// We need to save the max_early_data_size that the server sent us, in order
|
||||
// to decide if we're going to try 0-RTT with this ticket.
|
||||
// However, at the same time, the qtls.ClientSessionTicket needs to be equal to
|
||||
// the tls.ClientSessionTicket, so we can't just add a new field to the struct.
|
||||
// We therefore abuse the nonce field (which is a byte slice)
|
||||
nonceWithEarlyData := make([]byte, len(msg.nonce)+4)
|
||||
binary.BigEndian.PutUint32(nonceWithEarlyData, msg.maxEarlyData)
|
||||
copy(nonceWithEarlyData[4:], msg.nonce)
|
||||
|
||||
var appData []byte
|
||||
if c.extraConfig != nil && c.extraConfig.GetAppDataForSessionState != nil {
|
||||
appData = c.extraConfig.GetAppDataForSessionState()
|
||||
}
|
||||
var b cryptobyte.Builder
|
||||
b.AddUint16(clientSessionStateVersion) // revision
|
||||
b.AddUint32(msg.maxEarlyData)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(appData)
|
||||
})
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(msg.nonce)
|
||||
})
|
||||
|
||||
// Save the resumption_master_secret and nonce instead of deriving the PSK
|
||||
// to do the least amount of work on NewSessionTicket messages before we
|
||||
// know if the ticket will be used. Forward secrecy of resumed connections
|
||||
// is guaranteed by the requirement for pskModeDHE.
|
||||
session := &clientSessionState{
|
||||
sessionTicket: msg.label,
|
||||
vers: c.vers,
|
||||
cipherSuite: c.cipherSuite,
|
||||
masterSecret: c.resumptionSecret,
|
||||
serverCertificates: c.peerCertificates,
|
||||
verifiedChains: c.verifiedChains,
|
||||
receivedAt: c.config.time(),
|
||||
nonce: b.BytesOrPanic(),
|
||||
useBy: c.config.time().Add(lifetime),
|
||||
ageAdd: msg.ageAdd,
|
||||
ocspResponse: c.ocspResponse,
|
||||
scts: c.scts,
|
||||
}
|
||||
|
||||
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
|
||||
c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(session))
|
||||
|
||||
return nil
|
||||
}
|
||||
1875
vendor/github.com/quic-go/qtls-go1-19/handshake_messages.go
generated
vendored
1875
vendor/github.com/quic-go/qtls-go1-19/handshake_messages.go
generated
vendored
File diff suppressed because it is too large
Load Diff
922
vendor/github.com/quic-go/qtls-go1-19/handshake_server.go
generated
vendored
922
vendor/github.com/quic-go/qtls-go1-19/handshake_server.go
generated
vendored
@@ -1,922 +0,0 @@
|
||||
// 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 qtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
"crypto/subtle"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// serverHandshakeState contains details of a server handshake in progress.
|
||||
// It's discarded once the handshake has completed.
|
||||
type serverHandshakeState struct {
|
||||
c *Conn
|
||||
ctx context.Context
|
||||
clientHello *clientHelloMsg
|
||||
hello *serverHelloMsg
|
||||
suite *cipherSuite
|
||||
ecdheOk bool
|
||||
ecSignOk bool
|
||||
rsaDecryptOk bool
|
||||
rsaSignOk bool
|
||||
sessionState *sessionState
|
||||
finishedHash finishedHash
|
||||
masterSecret []byte
|
||||
cert *Certificate
|
||||
}
|
||||
|
||||
// serverHandshake performs a TLS handshake as a server.
|
||||
func (c *Conn) serverHandshake(ctx context.Context) error {
|
||||
c.setAlternativeRecordLayer()
|
||||
|
||||
clientHello, err := c.readClientHello(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.vers == VersionTLS13 {
|
||||
hs := serverHandshakeStateTLS13{
|
||||
c: c,
|
||||
ctx: ctx,
|
||||
clientHello: clientHello,
|
||||
}
|
||||
return hs.handshake()
|
||||
} else if c.extraConfig.usesAlternativeRecordLayer() {
|
||||
// This should already have been caught by the check that the ClientHello doesn't
|
||||
// offer any (supported) versions older than TLS 1.3.
|
||||
// Check again to make sure we can't be tricked into using an older version.
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return errors.New("tls: negotiated TLS < 1.3 when using QUIC")
|
||||
}
|
||||
|
||||
hs := serverHandshakeState{
|
||||
c: c,
|
||||
ctx: ctx,
|
||||
clientHello: clientHello,
|
||||
}
|
||||
return hs.handshake()
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) handshake() error {
|
||||
c := hs.c
|
||||
|
||||
if err := hs.processClientHello(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// For an overview of TLS handshaking, see RFC 5246, Section 7.3.
|
||||
c.buffering = true
|
||||
if hs.checkForResumption() {
|
||||
// The client has included a session ticket and so we do an abbreviated handshake.
|
||||
c.didResume = true
|
||||
if err := hs.doResumeHandshake(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.establishKeys(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendSessionTicket(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendFinished(c.serverFinished[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.clientFinishedIsFirst = false
|
||||
if err := hs.readFinished(nil); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// The client didn't include a session ticket, or it wasn't
|
||||
// valid so we do a full handshake.
|
||||
if err := hs.pickCipherSuite(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.doFullHandshake(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.establishKeys(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.readFinished(c.clientFinished[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
c.clientFinishedIsFirst = true
|
||||
c.buffering = true
|
||||
if err := hs.sendSessionTicket(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendFinished(nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random)
|
||||
atomic.StoreUint32(&c.handshakeStatus, 1)
|
||||
|
||||
c.updateConnectionState()
|
||||
return nil
|
||||
}
|
||||
|
||||
// readClientHello reads a ClientHello message and selects the protocol version.
|
||||
func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
|
||||
// clientHelloMsg is included in the transcript, but we haven't initialized
|
||||
// it yet. The respective handshake functions will record it themselves.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clientHello, ok := msg.(*clientHelloMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return nil, unexpectedMessageError(clientHello, msg)
|
||||
}
|
||||
|
||||
var configForClient *config
|
||||
originalConfig := c.config
|
||||
if c.config.GetConfigForClient != nil {
|
||||
chi := newClientHelloInfo(ctx, c, clientHello)
|
||||
if cfc, err := c.config.GetConfigForClient(chi); err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return nil, err
|
||||
} else if cfc != nil {
|
||||
configForClient = fromConfig(cfc)
|
||||
c.config = configForClient
|
||||
}
|
||||
}
|
||||
c.ticketKeys = originalConfig.ticketKeys(configForClient)
|
||||
|
||||
clientVersions := clientHello.supportedVersions
|
||||
if len(clientHello.supportedVersions) == 0 {
|
||||
clientVersions = supportedVersionsFromMax(clientHello.vers)
|
||||
}
|
||||
if c.extraConfig.usesAlternativeRecordLayer() {
|
||||
// In QUIC, the client MUST NOT offer any old TLS versions.
|
||||
// Here, we can only check that none of the other supported versions of this library
|
||||
// (TLS 1.0 - TLS 1.2) is offered. We don't check for any SSL versions here.
|
||||
for _, ver := range clientVersions {
|
||||
if ver == VersionTLS13 {
|
||||
continue
|
||||
}
|
||||
for _, v := range supportedVersions {
|
||||
if ver == v {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return nil, fmt.Errorf("tls: client offered old TLS version %#x", ver)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make the config we're using allows us to use TLS 1.3.
|
||||
if c.config.maxSupportedVersion(roleServer) < VersionTLS13 {
|
||||
c.sendAlert(alertInternalError)
|
||||
return nil, errors.New("tls: MaxVersion prevents QUIC from using TLS 1.3")
|
||||
}
|
||||
}
|
||||
c.vers, ok = c.config.mutualVersion(roleServer, clientVersions)
|
||||
if !ok {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions)
|
||||
}
|
||||
c.haveVers = true
|
||||
c.in.version = c.vers
|
||||
c.out.version = c.vers
|
||||
|
||||
return clientHello, nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) processClientHello() error {
|
||||
c := hs.c
|
||||
|
||||
hs.hello = new(serverHelloMsg)
|
||||
hs.hello.vers = c.vers
|
||||
|
||||
foundCompression := false
|
||||
// We only support null compression, so check that the client offered it.
|
||||
for _, compression := range hs.clientHello.compressionMethods {
|
||||
if compression == compressionNone {
|
||||
foundCompression = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !foundCompression {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return errors.New("tls: client does not support uncompressed connections")
|
||||
}
|
||||
|
||||
hs.hello.random = make([]byte, 32)
|
||||
serverRandom := hs.hello.random
|
||||
// Downgrade protection canaries. See RFC 8446, Section 4.1.3.
|
||||
maxVers := c.config.maxSupportedVersion(roleServer)
|
||||
if maxVers >= VersionTLS12 && c.vers < maxVers || testingOnlyForceDowngradeCanary {
|
||||
if c.vers == VersionTLS12 {
|
||||
copy(serverRandom[24:], downgradeCanaryTLS12)
|
||||
} else {
|
||||
copy(serverRandom[24:], downgradeCanaryTLS11)
|
||||
}
|
||||
serverRandom = serverRandom[:24]
|
||||
}
|
||||
_, err := io.ReadFull(c.config.rand(), serverRandom)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(hs.clientHello.secureRenegotiation) != 0 {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return errors.New("tls: initial handshake had non-empty renegotiation extension")
|
||||
}
|
||||
|
||||
hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
|
||||
hs.hello.compressionMethod = compressionNone
|
||||
if len(hs.clientHello.serverName) > 0 {
|
||||
c.serverName = hs.clientHello.serverName
|
||||
}
|
||||
|
||||
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(hs.ctx, c, hs.clientHello))
|
||||
if err != nil {
|
||||
if err == errNoCertificates {
|
||||
c.sendAlert(alertUnrecognizedName)
|
||||
} else {
|
||||
c.sendAlert(alertInternalError)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if hs.clientHello.scts {
|
||||
hs.hello.scts = hs.cert.SignedCertificateTimestamps
|
||||
}
|
||||
|
||||
hs.ecdheOk = supportsECDHE(c.config, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints)
|
||||
|
||||
if hs.ecdheOk && len(hs.clientHello.supportedPoints) > 0 {
|
||||
// Although omitting the ec_point_formats extension is permitted, some
|
||||
// old OpenSSL version will refuse to handshake if not present.
|
||||
//
|
||||
// Per RFC 4492, section 5.1.2, implementations MUST support the
|
||||
// uncompressed point format. See golang.org/issue/31943.
|
||||
hs.hello.supportedPoints = []uint8{pointFormatUncompressed}
|
||||
}
|
||||
|
||||
if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
|
||||
switch priv.Public().(type) {
|
||||
case *ecdsa.PublicKey:
|
||||
hs.ecSignOk = true
|
||||
case ed25519.PublicKey:
|
||||
hs.ecSignOk = true
|
||||
case *rsa.PublicKey:
|
||||
hs.rsaSignOk = true
|
||||
default:
|
||||
c.sendAlert(alertInternalError)
|
||||
return fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
|
||||
}
|
||||
}
|
||||
if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
|
||||
switch priv.Public().(type) {
|
||||
case *rsa.PublicKey:
|
||||
hs.rsaDecryptOk = true
|
||||
default:
|
||||
c.sendAlert(alertInternalError)
|
||||
return fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
supportsCurve := false
|
||||
for _, curve := range supportedCurves {
|
||||
if c.supportsCurve(curve) {
|
||||
supportsCurve = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
supportsPointFormat := false
|
||||
for _, pointFormat := range supportedPoints {
|
||||
if pointFormat == pointFormatUncompressed {
|
||||
supportsPointFormat = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// Per RFC 8422, Section 5.1.2, if the Supported Point Formats extension is
|
||||
// missing, uncompressed points are supported. If supportedPoints is empty,
|
||||
// the extension must be missing, as an empty extension body is rejected by
|
||||
// the parser. See https://go.dev/issue/49126.
|
||||
if len(supportedPoints) == 0 {
|
||||
supportsPointFormat = true
|
||||
}
|
||||
|
||||
return supportsCurve && supportsPointFormat
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) pickCipherSuite() error {
|
||||
c := hs.c
|
||||
|
||||
preferenceOrder := cipherSuitesPreferenceOrder
|
||||
if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
|
||||
preferenceOrder = cipherSuitesPreferenceOrderNoAES
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
c.cipherSuite = hs.suite.id
|
||||
|
||||
for _, id := range hs.clientHello.cipherSuites {
|
||||
if id == TLS_FALLBACK_SCSV {
|
||||
// The client is doing a fallback connection. See RFC 7507.
|
||||
if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer) {
|
||||
c.sendAlert(alertInappropriateFallback)
|
||||
return errors.New("tls: client using inappropriate protocol fallback")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) cipherSuiteOk(c *cipherSuite) bool {
|
||||
if c.flags&suiteECDHE != 0 {
|
||||
if !hs.ecdheOk {
|
||||
return false
|
||||
}
|
||||
if c.flags&suiteECSign != 0 {
|
||||
if !hs.ecSignOk {
|
||||
return false
|
||||
}
|
||||
} else if !hs.rsaSignOk {
|
||||
return false
|
||||
}
|
||||
} else if !hs.rsaDecryptOk {
|
||||
return false
|
||||
}
|
||||
if hs.c.vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// checkForResumption reports whether we should perform resumption on this connection.
|
||||
func (hs *serverHandshakeState) checkForResumption() bool {
|
||||
c := hs.c
|
||||
|
||||
if c.config.SessionTicketsDisabled {
|
||||
return false
|
||||
}
|
||||
|
||||
plaintext, usedOldKey := c.decryptTicket(hs.clientHello.sessionTicket)
|
||||
if plaintext == nil {
|
||||
return false
|
||||
}
|
||||
hs.sessionState = &sessionState{usedOldKey: usedOldKey}
|
||||
ok := hs.sessionState.unmarshal(plaintext)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
createdAt := time.Unix(int64(hs.sessionState.createdAt), 0)
|
||||
if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
|
||||
return false
|
||||
}
|
||||
|
||||
// Never resume a session for a different TLS version.
|
||||
if c.vers != hs.sessionState.vers {
|
||||
return false
|
||||
}
|
||||
|
||||
cipherSuiteOk := false
|
||||
// Check that the client is still offering the ciphersuite in the session.
|
||||
for _, id := range hs.clientHello.cipherSuites {
|
||||
if id == hs.sessionState.cipherSuite {
|
||||
cipherSuiteOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !cipherSuiteOk {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check that we also support the ciphersuite from the session.
|
||||
hs.suite = selectCipherSuite([]uint16{hs.sessionState.cipherSuite},
|
||||
c.config.cipherSuites(), hs.cipherSuiteOk)
|
||||
if hs.suite == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
sessionHasClientCerts := len(hs.sessionState.certificates) != 0
|
||||
needClientCerts := requiresClientCert(c.config.ClientAuth)
|
||||
if needClientCerts && !sessionHasClientCerts {
|
||||
return false
|
||||
}
|
||||
if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) doResumeHandshake() error {
|
||||
c := hs.c
|
||||
|
||||
hs.hello.cipherSuite = hs.suite.id
|
||||
c.cipherSuite = hs.suite.id
|
||||
// We echo the client's session ID in the ServerHello to let it know
|
||||
// that we're doing a resumption.
|
||||
hs.hello.sessionId = hs.clientHello.sessionId
|
||||
hs.hello.ticketSupported = hs.sessionState.usedOldKey
|
||||
hs.finishedHash = newFinishedHash(c.vers, hs.suite)
|
||||
hs.finishedHash.discardHandshakeBuffer()
|
||||
if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.processCertsFromClient(Certificate{
|
||||
Certificate: hs.sessionState.certificates,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.config.VerifyConnection != nil {
|
||||
if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
hs.masterSecret = hs.sessionState.masterSecret
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
c := hs.c
|
||||
|
||||
if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
|
||||
hs.hello.ocspStapling = true
|
||||
}
|
||||
|
||||
hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
|
||||
hs.hello.cipherSuite = hs.suite.id
|
||||
|
||||
hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
|
||||
if c.config.ClientAuth == NoClientCert {
|
||||
// No need to keep a full record of the handshake if client
|
||||
// certificates won't be used.
|
||||
hs.finishedHash.discardHandshakeBuffer()
|
||||
}
|
||||
if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certMsg := new(certificateMsg)
|
||||
certMsg.certificates = hs.cert.Certificate
|
||||
if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hs.hello.ocspStapling {
|
||||
certStatus := new(certificateStatusMsg)
|
||||
certStatus.response = hs.cert.OCSPStaple
|
||||
if _, err := hs.c.writeHandshakeRecord(certStatus, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
keyAgreement := hs.suite.ka(c.vers)
|
||||
skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello)
|
||||
if err != nil {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return err
|
||||
}
|
||||
if skx != nil {
|
||||
if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var certReq *certificateRequestMsg
|
||||
if c.config.ClientAuth >= RequestClientCert {
|
||||
// Request a client certificate
|
||||
certReq = new(certificateRequestMsg)
|
||||
certReq.certificateTypes = []byte{
|
||||
byte(certTypeRSASign),
|
||||
byte(certTypeECDSASign),
|
||||
}
|
||||
if c.vers >= VersionTLS12 {
|
||||
certReq.hasSignatureAlgorithm = true
|
||||
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
|
||||
}
|
||||
|
||||
// An empty list of certificateAuthorities signals to
|
||||
// the client that it may send any certificate in response
|
||||
// to our request. When we know the CAs we trust, then
|
||||
// we can send them down, so that the client can choose
|
||||
// an appropriate certificate to give to us.
|
||||
if c.config.ClientCAs != nil {
|
||||
certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
|
||||
}
|
||||
if _, err := hs.c.writeHandshakeRecord(certReq, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
helloDone := new(serverHelloDoneMsg)
|
||||
if _, err := hs.c.writeHandshakeRecord(helloDone, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pub crypto.PublicKey // public key for client auth, if any
|
||||
|
||||
msg, err := c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we requested a client certificate, then the client must send a
|
||||
// certificate message, even if it's empty.
|
||||
if c.config.ClientAuth >= RequestClientCert {
|
||||
certMsg, ok := msg.(*certificateMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
|
||||
if err := c.processCertsFromClient(Certificate{
|
||||
Certificate: certMsg.certificates,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(certMsg.certificates) != 0 {
|
||||
pub = c.peerCertificates[0].PublicKey
|
||||
}
|
||||
|
||||
msg, err = c.readHandshake(&hs.finishedHash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if c.config.VerifyConnection != nil {
|
||||
if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Get client key exchange
|
||||
ckx, ok := msg.(*clientKeyExchangeMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(ckx, msg)
|
||||
}
|
||||
|
||||
preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
|
||||
if err != nil {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return err
|
||||
}
|
||||
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
|
||||
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
|
||||
// If we received a client cert in response to our certificate request message,
|
||||
// the client will send us a certificateVerifyMsg immediately after the
|
||||
// clientKeyExchangeMsg. This message is a digest of all preceding
|
||||
// handshake-layer messages that is signed using the private key corresponding
|
||||
// to the client's certificate. This allows us to verify that the client is in
|
||||
// possession of the private key of the certificate.
|
||||
if len(c.peerCertificates) > 0 {
|
||||
// certificateVerifyMsg is included in the transcript, but not until
|
||||
// after we verify the handshake signature, since the state before
|
||||
// this message was sent is used.
|
||||
msg, err = c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
certVerify, ok := msg.(*certificateVerifyMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certVerify, msg)
|
||||
}
|
||||
|
||||
var sigType uint8
|
||||
var sigHash crypto.Hash
|
||||
if c.vers >= VersionTLS12 {
|
||||
if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, certReq.supportedSignatureAlgorithms) {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: client certificate used with invalid signature algorithm")
|
||||
}
|
||||
sigType, sigHash, err = typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
} else {
|
||||
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub)
|
||||
if err != nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash, hs.masterSecret)
|
||||
if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil {
|
||||
c.sendAlert(alertDecryptError)
|
||||
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
|
||||
}
|
||||
|
||||
if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
hs.finishedHash.discardHandshakeBuffer()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) establishKeys() error {
|
||||
c := hs.c
|
||||
|
||||
clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
|
||||
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 any
|
||||
var clientHash, serverHash hash.Hash
|
||||
|
||||
if hs.suite.aead == nil {
|
||||
clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
|
||||
clientHash = hs.suite.mac(clientMAC)
|
||||
serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
|
||||
serverHash = hs.suite.mac(serverMAC)
|
||||
} else {
|
||||
clientCipher = hs.suite.aead(clientKey, clientIV)
|
||||
serverCipher = hs.suite.aead(serverKey, serverIV)
|
||||
}
|
||||
|
||||
c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
|
||||
c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) readFinished(out []byte) error {
|
||||
c := hs.c
|
||||
|
||||
if err := c.readChangeCipherSpec(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clientFinished, ok := msg.(*finishedMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(clientFinished, msg)
|
||||
}
|
||||
|
||||
verify := hs.finishedHash.clientSum(hs.masterSecret)
|
||||
if len(verify) != len(clientFinished.verifyData) ||
|
||||
subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return errors.New("tls: client's Finished message is incorrect")
|
||||
}
|
||||
|
||||
if err := transcriptMsg(clientFinished, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copy(out, verify)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) sendSessionTicket() error {
|
||||
// ticketSupported is set in a resumption handshake if the
|
||||
// ticket from the client was encrypted with an old session
|
||||
// ticket key and thus a refreshed ticket should be sent.
|
||||
if !hs.hello.ticketSupported {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := hs.c
|
||||
m := new(newSessionTicketMsg)
|
||||
|
||||
createdAt := uint64(c.config.time().Unix())
|
||||
if hs.sessionState != nil {
|
||||
// If this is re-wrapping an old key, then keep
|
||||
// the original time it was created.
|
||||
createdAt = hs.sessionState.createdAt
|
||||
}
|
||||
|
||||
var certsFromClient [][]byte
|
||||
for _, cert := range c.peerCertificates {
|
||||
certsFromClient = append(certsFromClient, cert.Raw)
|
||||
}
|
||||
state := sessionState{
|
||||
vers: c.vers,
|
||||
cipherSuite: hs.suite.id,
|
||||
createdAt: createdAt,
|
||||
masterSecret: hs.masterSecret,
|
||||
certificates: certsFromClient,
|
||||
}
|
||||
stateBytes, err := state.marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.ticket, err = c.encryptTicket(stateBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(m, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeState) sendFinished(out []byte) error {
|
||||
c := hs.c
|
||||
|
||||
if err := c.writeChangeCipherRecord(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
finished := new(finishedMsg)
|
||||
finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
|
||||
if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copy(out, finished.verifyData)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// processCertsFromClient takes a chain of client certificates either from a
|
||||
// Certificates message or from a sessionState and verifies them. It returns
|
||||
// the public key of the leaf certificate.
|
||||
func (c *Conn) processCertsFromClient(certificate Certificate) error {
|
||||
certificates := certificate.Certificate
|
||||
certs := make([]*x509.Certificate, len(certificates))
|
||||
var err error
|
||||
for i, asn1Data := range certificates {
|
||||
if certs[i], err = x509.ParseCertificate(asn1Data); err != nil {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return errors.New("tls: failed to parse client certificate: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return errors.New("tls: client didn't provide a certificate")
|
||||
}
|
||||
|
||||
if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: c.config.ClientCAs,
|
||||
CurrentTime: c.config.time(),
|
||||
Intermediates: x509.NewCertPool(),
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
|
||||
}
|
||||
|
||||
for _, cert := range certs[1:] {
|
||||
opts.Intermediates.AddCert(cert)
|
||||
}
|
||||
|
||||
chains, err := certs[0].Verify(opts)
|
||||
if err != nil {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return errors.New("tls: failed to verify client certificate: " + err.Error())
|
||||
}
|
||||
|
||||
c.verifiedChains = chains
|
||||
}
|
||||
|
||||
c.peerCertificates = certs
|
||||
c.ocspResponse = certificate.OCSPStaple
|
||||
c.scts = certificate.SignedCertificateTimestamps
|
||||
|
||||
if len(certs) > 0 {
|
||||
switch certs[0].PublicKey.(type) {
|
||||
case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
|
||||
default:
|
||||
c.sendAlert(alertUnsupportedCertificate)
|
||||
return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
|
||||
}
|
||||
}
|
||||
|
||||
if c.config.VerifyPeerCertificate != nil {
|
||||
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newClientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
|
||||
supportedVersions := clientHello.supportedVersions
|
||||
if len(clientHello.supportedVersions) == 0 {
|
||||
supportedVersions = supportedVersionsFromMax(clientHello.vers)
|
||||
}
|
||||
|
||||
return toClientHelloInfo(&clientHelloInfo{
|
||||
CipherSuites: clientHello.cipherSuites,
|
||||
ServerName: clientHello.serverName,
|
||||
SupportedCurves: clientHello.supportedCurves,
|
||||
SupportedPoints: clientHello.supportedPoints,
|
||||
SignatureSchemes: clientHello.supportedSignatureAlgorithms,
|
||||
SupportedProtos: clientHello.alpnProtocols,
|
||||
SupportedVersions: supportedVersions,
|
||||
Conn: c.conn,
|
||||
config: toConfig(c.config),
|
||||
ctx: ctx,
|
||||
})
|
||||
}
|
||||
903
vendor/github.com/quic-go/qtls-go1-19/handshake_server_tls13.go
generated
vendored
903
vendor/github.com/quic-go/qtls-go1-19/handshake_server_tls13.go
generated
vendored
@@ -1,903 +0,0 @@
|
||||
// Copyright 2018 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 qtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
"crypto/rsa"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// maxClientPSKIdentities is the number of client PSK identities the server will
|
||||
// attempt to validate. It will ignore the rest not to let cheap ClientHello
|
||||
// messages cause too much work in session ticket decryption attempts.
|
||||
const maxClientPSKIdentities = 5
|
||||
|
||||
type serverHandshakeStateTLS13 struct {
|
||||
c *Conn
|
||||
ctx context.Context
|
||||
clientHello *clientHelloMsg
|
||||
hello *serverHelloMsg
|
||||
alpnNegotiationErr error
|
||||
encryptedExtensions *encryptedExtensionsMsg
|
||||
sentDummyCCS bool
|
||||
usingPSK bool
|
||||
suite *cipherSuiteTLS13
|
||||
cert *Certificate
|
||||
sigAlg SignatureScheme
|
||||
earlySecret []byte
|
||||
sharedKey []byte
|
||||
handshakeSecret []byte
|
||||
masterSecret []byte
|
||||
trafficSecret []byte // client_application_traffic_secret_0
|
||||
transcript hash.Hash
|
||||
clientFinished []byte
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) handshake() error {
|
||||
c := hs.c
|
||||
|
||||
if needFIPS() {
|
||||
return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
|
||||
}
|
||||
|
||||
// For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2.
|
||||
if err := hs.processClientHello(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.checkForResumption(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.updateConnectionState()
|
||||
if err := hs.pickCertificate(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.buffering = true
|
||||
if err := hs.sendServerParameters(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendServerCertificate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendServerFinished(); err != nil {
|
||||
return err
|
||||
}
|
||||
// Note that at this point we could start sending application data without
|
||||
// waiting for the client's second flight, but the application might not
|
||||
// expect the lack of replay protection of the ClientHello parameters.
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.readClientCertificate(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.updateConnectionState()
|
||||
if err := hs.readClientFinished(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
atomic.StoreUint32(&c.handshakeStatus, 1)
|
||||
c.updateConnectionState()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) processClientHello() error {
|
||||
c := hs.c
|
||||
|
||||
hs.hello = new(serverHelloMsg)
|
||||
hs.encryptedExtensions = new(encryptedExtensionsMsg)
|
||||
|
||||
// TLS 1.3 froze the ServerHello.legacy_version field, and uses
|
||||
// supported_versions instead. See RFC 8446, sections 4.1.3 and 4.2.1.
|
||||
hs.hello.vers = VersionTLS12
|
||||
hs.hello.supportedVersion = c.vers
|
||||
|
||||
if len(hs.clientHello.supportedVersions) == 0 {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: client used the legacy version field to negotiate TLS 1.3")
|
||||
}
|
||||
|
||||
// Abort if the client is doing a fallback and landing lower than what we
|
||||
// support. See RFC 7507, which however does not specify the interaction
|
||||
// with supported_versions. The only difference is that with
|
||||
// supported_versions a client has a chance to attempt a [TLS 1.2, TLS 1.4]
|
||||
// handshake in case TLS 1.3 is broken but 1.2 is not. Alas, in that case,
|
||||
// it will have to drop the TLS_FALLBACK_SCSV protection if it falls back to
|
||||
// TLS 1.2, because a TLS 1.3 server would abort here. The situation before
|
||||
// supported_versions was not better because there was just no way to do a
|
||||
// TLS 1.4 handshake without risking the server selecting TLS 1.3.
|
||||
for _, id := range hs.clientHello.cipherSuites {
|
||||
if id == TLS_FALLBACK_SCSV {
|
||||
// Use c.vers instead of max(supported_versions) because an attacker
|
||||
// could defeat this by adding an arbitrary high version otherwise.
|
||||
if c.vers < c.config.maxSupportedVersion(roleServer) {
|
||||
c.sendAlert(alertInappropriateFallback)
|
||||
return errors.New("tls: client using inappropriate protocol fallback")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(hs.clientHello.compressionMethods) != 1 ||
|
||||
hs.clientHello.compressionMethods[0] != compressionNone {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: TLS 1.3 client supports illegal compression methods")
|
||||
}
|
||||
|
||||
hs.hello.random = make([]byte, 32)
|
||||
if _, err := io.ReadFull(c.config.rand(), hs.hello.random); err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(hs.clientHello.secureRenegotiation) != 0 {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return errors.New("tls: initial handshake had non-empty renegotiation extension")
|
||||
}
|
||||
|
||||
hs.hello.sessionId = hs.clientHello.sessionId
|
||||
hs.hello.compressionMethod = compressionNone
|
||||
|
||||
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 {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return errors.New("tls: no cipher suite supported by both client and server")
|
||||
}
|
||||
c.cipherSuite = hs.suite.id
|
||||
hs.hello.cipherSuite = hs.suite.id
|
||||
hs.transcript = hs.suite.hash.New()
|
||||
|
||||
// Pick the ECDHE group in server preference order, but give priority to
|
||||
// groups with a key share, to avoid a HelloRetryRequest round-trip.
|
||||
var selectedGroup CurveID
|
||||
var clientKeyShare *keyShare
|
||||
GroupSelection:
|
||||
for _, preferredGroup := range c.config.curvePreferences() {
|
||||
for _, ks := range hs.clientHello.keyShares {
|
||||
if ks.group == preferredGroup {
|
||||
selectedGroup = ks.group
|
||||
clientKeyShare = &ks
|
||||
break GroupSelection
|
||||
}
|
||||
}
|
||||
if selectedGroup != 0 {
|
||||
continue
|
||||
}
|
||||
for _, group := range hs.clientHello.supportedCurves {
|
||||
if group == preferredGroup {
|
||||
selectedGroup = group
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if selectedGroup == 0 {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return errors.New("tls: no ECDHE curve supported by both client and server")
|
||||
}
|
||||
if clientKeyShare == nil {
|
||||
if err := hs.doHelloRetryRequest(selectedGroup); err != nil {
|
||||
return err
|
||||
}
|
||||
clientKeyShare = &hs.clientHello.keyShares[0]
|
||||
}
|
||||
|
||||
if _, ok := curveForCurveID(selectedGroup); selectedGroup != X25519 && !ok {
|
||||
c.sendAlert(alertInternalError)
|
||||
return errors.New("tls: CurvePreferences includes unsupported curve")
|
||||
}
|
||||
params, err := generateECDHEParameters(c.config.rand(), selectedGroup)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
hs.hello.serverShare = keyShare{group: selectedGroup, data: params.PublicKey()}
|
||||
hs.sharedKey = params.SharedKey(clientKeyShare.data)
|
||||
if hs.sharedKey == nil {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: invalid client key share")
|
||||
}
|
||||
|
||||
c.serverName = hs.clientHello.serverName
|
||||
|
||||
if c.extraConfig != nil && c.extraConfig.ReceivedExtensions != nil {
|
||||
c.extraConfig.ReceivedExtensions(typeClientHello, hs.clientHello.additionalExtensions)
|
||||
}
|
||||
|
||||
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
|
||||
if err != nil {
|
||||
hs.alpnNegotiationErr = err
|
||||
}
|
||||
hs.encryptedExtensions.alpnProtocol = selectedProto
|
||||
c.clientProtocol = selectedProto
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) checkForResumption() error {
|
||||
c := hs.c
|
||||
|
||||
if c.config.SessionTicketsDisabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
modeOK := false
|
||||
for _, mode := range hs.clientHello.pskModes {
|
||||
if mode == pskModeDHE {
|
||||
modeOK = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !modeOK {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(hs.clientHello.pskIdentities) != len(hs.clientHello.pskBinders) {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: invalid or missing PSK binders")
|
||||
}
|
||||
if len(hs.clientHello.pskIdentities) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i, identity := range hs.clientHello.pskIdentities {
|
||||
if i >= maxClientPSKIdentities {
|
||||
break
|
||||
}
|
||||
|
||||
plaintext, _ := c.decryptTicket(identity.label)
|
||||
if plaintext == nil {
|
||||
continue
|
||||
}
|
||||
sessionState := new(sessionStateTLS13)
|
||||
if ok := sessionState.unmarshal(plaintext); !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if hs.clientHello.earlyData {
|
||||
if sessionState.maxEarlyData == 0 {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
return errors.New("tls: client sent unexpected early data")
|
||||
}
|
||||
|
||||
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
|
||||
c.used0RTT = true
|
||||
}
|
||||
}
|
||||
|
||||
createdAt := time.Unix(int64(sessionState.createdAt), 0)
|
||||
if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
|
||||
continue
|
||||
}
|
||||
|
||||
// We don't check the obfuscated ticket age because it's affected by
|
||||
// clock skew and it's only a freshness signal useful for shrinking the
|
||||
// window for replay attacks, which don't affect us as we don't do 0-RTT.
|
||||
|
||||
pskSuite := cipherSuiteTLS13ByID(sessionState.cipherSuite)
|
||||
if pskSuite == nil || pskSuite.hash != hs.suite.hash {
|
||||
continue
|
||||
}
|
||||
|
||||
// PSK connections don't re-establish client certificates, but carry
|
||||
// them over in the session ticket. Ensure the presence of client certs
|
||||
// in the ticket is consistent with the configured requirements.
|
||||
sessionHasClientCerts := len(sessionState.certificate.Certificate) != 0
|
||||
needClientCerts := requiresClientCert(c.config.ClientAuth)
|
||||
if needClientCerts && !sessionHasClientCerts {
|
||||
continue
|
||||
}
|
||||
if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
|
||||
continue
|
||||
}
|
||||
|
||||
psk := hs.suite.expandLabel(sessionState.resumptionSecret, "resumption",
|
||||
nil, hs.suite.hash.Size())
|
||||
hs.earlySecret = hs.suite.extract(psk, nil)
|
||||
binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil)
|
||||
// Clone the transcript in case a HelloRetryRequest was recorded.
|
||||
transcript := cloneHash(hs.transcript, hs.suite.hash)
|
||||
if transcript == nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return errors.New("tls: internal error: failed to clone hash")
|
||||
}
|
||||
clientHelloBytes, err := hs.clientHello.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
transcript.Write(clientHelloBytes)
|
||||
pskBinder := hs.suite.finishedHash(binderKey, transcript)
|
||||
if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) {
|
||||
c.sendAlert(alertDecryptError)
|
||||
return errors.New("tls: invalid PSK binder")
|
||||
}
|
||||
|
||||
c.didResume = true
|
||||
if err := c.processCertsFromClient(sessionState.certificate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h := cloneHash(hs.transcript, hs.suite.hash)
|
||||
clientHelloWithBindersBytes, err := hs.clientHello.marshal()
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
h.Write(clientHelloWithBindersBytes)
|
||||
if hs.encryptedExtensions.earlyData {
|
||||
clientEarlySecret := hs.suite.deriveSecret(hs.earlySecret, "c e traffic", h)
|
||||
c.in.exportKey(Encryption0RTT, hs.suite, clientEarlySecret)
|
||||
if err := c.config.writeKeyLog(keyLogLabelEarlyTraffic, hs.clientHello.random, clientEarlySecret); err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
hs.hello.selectedIdentityPresent = true
|
||||
hs.hello.selectedIdentity = uint16(i)
|
||||
hs.usingPSK = true
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cloneHash uses the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler
|
||||
// interfaces implemented by standard library hashes to clone the state of in
|
||||
// to a new instance of h. It returns nil if the operation fails.
|
||||
func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash {
|
||||
// Recreate the interface to avoid importing encoding.
|
||||
type binaryMarshaler interface {
|
||||
MarshalBinary() (data []byte, err error)
|
||||
UnmarshalBinary(data []byte) error
|
||||
}
|
||||
marshaler, ok := in.(binaryMarshaler)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
state, err := marshaler.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
out := h.New()
|
||||
unmarshaler, ok := out.(binaryMarshaler)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if err := unmarshaler.UnmarshalBinary(state); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) pickCertificate() error {
|
||||
c := hs.c
|
||||
|
||||
// Only one of PSK and certificates are used at a time.
|
||||
if hs.usingPSK {
|
||||
return nil
|
||||
}
|
||||
|
||||
// signature_algorithms is required in TLS 1.3. See RFC 8446, Section 4.2.3.
|
||||
if len(hs.clientHello.supportedSignatureAlgorithms) == 0 {
|
||||
return c.sendAlert(alertMissingExtension)
|
||||
}
|
||||
|
||||
certificate, err := c.config.getCertificate(newClientHelloInfo(hs.ctx, c, hs.clientHello))
|
||||
if err != nil {
|
||||
if err == errNoCertificates {
|
||||
c.sendAlert(alertUnrecognizedName)
|
||||
} else {
|
||||
c.sendAlert(alertInternalError)
|
||||
}
|
||||
return err
|
||||
}
|
||||
hs.sigAlg, err = selectSignatureScheme(c.vers, certificate, hs.clientHello.supportedSignatureAlgorithms)
|
||||
if err != nil {
|
||||
// getCertificate returned a certificate that is unsupported or
|
||||
// incompatible with the client's signature algorithms.
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return err
|
||||
}
|
||||
hs.cert = certificate
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
|
||||
// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
|
||||
func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
|
||||
if hs.sentDummyCCS {
|
||||
return nil
|
||||
}
|
||||
hs.sentDummyCCS = true
|
||||
|
||||
return hs.c.writeChangeCipherRecord()
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error {
|
||||
c := hs.c
|
||||
|
||||
// The first ClientHello gets double-hashed into the transcript upon a
|
||||
// HelloRetryRequest. See RFC 8446, Section 4.4.1.
|
||||
if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
chHash := hs.transcript.Sum(nil)
|
||||
hs.transcript.Reset()
|
||||
hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
||||
hs.transcript.Write(chHash)
|
||||
|
||||
helloRetryRequest := &serverHelloMsg{
|
||||
vers: hs.hello.vers,
|
||||
random: helloRetryRequestRandom,
|
||||
sessionId: hs.hello.sessionId,
|
||||
cipherSuite: hs.hello.cipherSuite,
|
||||
compressionMethod: hs.hello.compressionMethod,
|
||||
supportedVersion: hs.hello.supportedVersion,
|
||||
selectedGroup: selectedGroup,
|
||||
}
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// clientHelloMsg is not included in the transcript.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
clientHello, ok := msg.(*clientHelloMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(clientHello, msg)
|
||||
}
|
||||
|
||||
if len(clientHello.keyShares) != 1 || clientHello.keyShares[0].group != selectedGroup {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: client sent invalid key share in second ClientHello")
|
||||
}
|
||||
|
||||
if clientHello.earlyData {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: client indicated early data in second ClientHello")
|
||||
}
|
||||
|
||||
if illegalClientHelloChange(clientHello, hs.clientHello) {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: client illegally modified second ClientHello")
|
||||
}
|
||||
|
||||
if clientHello.earlyData {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: client offered 0-RTT data in second ClientHello")
|
||||
}
|
||||
|
||||
hs.clientHello = clientHello
|
||||
return nil
|
||||
}
|
||||
|
||||
// illegalClientHelloChange reports whether the two ClientHello messages are
|
||||
// different, with the exception of the changes allowed before and after a
|
||||
// HelloRetryRequest. See RFC 8446, Section 4.1.2.
|
||||
func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool {
|
||||
if len(ch.supportedVersions) != len(ch1.supportedVersions) ||
|
||||
len(ch.cipherSuites) != len(ch1.cipherSuites) ||
|
||||
len(ch.supportedCurves) != len(ch1.supportedCurves) ||
|
||||
len(ch.supportedSignatureAlgorithms) != len(ch1.supportedSignatureAlgorithms) ||
|
||||
len(ch.supportedSignatureAlgorithmsCert) != len(ch1.supportedSignatureAlgorithmsCert) ||
|
||||
len(ch.alpnProtocols) != len(ch1.alpnProtocols) {
|
||||
return true
|
||||
}
|
||||
for i := range ch.supportedVersions {
|
||||
if ch.supportedVersions[i] != ch1.supportedVersions[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for i := range ch.cipherSuites {
|
||||
if ch.cipherSuites[i] != ch1.cipherSuites[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for i := range ch.supportedCurves {
|
||||
if ch.supportedCurves[i] != ch1.supportedCurves[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for i := range ch.supportedSignatureAlgorithms {
|
||||
if ch.supportedSignatureAlgorithms[i] != ch1.supportedSignatureAlgorithms[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for i := range ch.supportedSignatureAlgorithmsCert {
|
||||
if ch.supportedSignatureAlgorithmsCert[i] != ch1.supportedSignatureAlgorithmsCert[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for i := range ch.alpnProtocols {
|
||||
if ch.alpnProtocols[i] != ch1.alpnProtocols[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return ch.vers != ch1.vers ||
|
||||
!bytes.Equal(ch.random, ch1.random) ||
|
||||
!bytes.Equal(ch.sessionId, ch1.sessionId) ||
|
||||
!bytes.Equal(ch.compressionMethods, ch1.compressionMethods) ||
|
||||
ch.serverName != ch1.serverName ||
|
||||
ch.ocspStapling != ch1.ocspStapling ||
|
||||
!bytes.Equal(ch.supportedPoints, ch1.supportedPoints) ||
|
||||
ch.ticketSupported != ch1.ticketSupported ||
|
||||
!bytes.Equal(ch.sessionTicket, ch1.sessionTicket) ||
|
||||
ch.secureRenegotiationSupported != ch1.secureRenegotiationSupported ||
|
||||
!bytes.Equal(ch.secureRenegotiation, ch1.secureRenegotiation) ||
|
||||
ch.scts != ch1.scts ||
|
||||
!bytes.Equal(ch.cookie, ch1.cookie) ||
|
||||
!bytes.Equal(ch.pskModes, ch1.pskModes)
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
|
||||
c := hs.c
|
||||
|
||||
if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
earlySecret := hs.earlySecret
|
||||
if earlySecret == nil {
|
||||
earlySecret = hs.suite.extract(nil, nil)
|
||||
}
|
||||
hs.handshakeSecret = hs.suite.extract(hs.sharedKey,
|
||||
hs.suite.deriveSecret(earlySecret, "derived", nil))
|
||||
|
||||
clientSecret := hs.suite.deriveSecret(hs.handshakeSecret,
|
||||
clientHandshakeTrafficLabel, hs.transcript)
|
||||
c.in.exportKey(EncryptionHandshake, hs.suite, clientSecret)
|
||||
c.in.setTrafficSecret(hs.suite, clientSecret)
|
||||
serverSecret := hs.suite.deriveSecret(hs.handshakeSecret,
|
||||
serverHandshakeTrafficLabel, hs.transcript)
|
||||
c.out.exportKey(EncryptionHandshake, hs.suite, serverSecret)
|
||||
c.out.setTrafficSecret(hs.suite, serverSecret)
|
||||
|
||||
err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.clientHello.random, serverSecret)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
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)
|
||||
}
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.encryptedExtensions, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) requestClientCert() bool {
|
||||
return hs.c.config.ClientAuth >= RequestClientCert && !hs.usingPSK
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
|
||||
c := hs.c
|
||||
|
||||
// Only one of PSK and certificates are used at a time.
|
||||
if hs.usingPSK {
|
||||
return nil
|
||||
}
|
||||
|
||||
if hs.requestClientCert() {
|
||||
// Request a client certificate
|
||||
certReq := new(certificateRequestMsgTLS13)
|
||||
certReq.ocspStapling = true
|
||||
certReq.scts = true
|
||||
certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
|
||||
if c.config.ClientCAs != nil {
|
||||
certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
|
||||
}
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(certReq, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
certMsg := new(certificateMsgTLS13)
|
||||
|
||||
certMsg.certificate = *hs.cert
|
||||
certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0
|
||||
certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certVerifyMsg := new(certificateVerifyMsg)
|
||||
certVerifyMsg.hasSignatureAlgorithm = true
|
||||
certVerifyMsg.signatureAlgorithm = hs.sigAlg
|
||||
|
||||
sigType, sigHash, err := typeAndHashFromSignatureScheme(hs.sigAlg)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
|
||||
signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
|
||||
signOpts := crypto.SignerOpts(sigHash)
|
||||
if sigType == signatureRSAPSS {
|
||||
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
|
||||
}
|
||||
sig, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts)
|
||||
if err != nil {
|
||||
public := hs.cert.PrivateKey.(crypto.Signer).Public()
|
||||
if rsaKey, ok := public.(*rsa.PublicKey); ok && sigType == signatureRSAPSS &&
|
||||
rsaKey.N.BitLen()/8 < sigHash.Size()*2+2 { // key too small for RSA-PSS
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
} else {
|
||||
c.sendAlert(alertInternalError)
|
||||
}
|
||||
return errors.New("tls: failed to sign handshake: " + err.Error())
|
||||
}
|
||||
certVerifyMsg.signature = sig
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
|
||||
c := hs.c
|
||||
|
||||
finished := &finishedMsg{
|
||||
verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
|
||||
}
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Derive secrets that take context through the server Finished.
|
||||
|
||||
hs.masterSecret = hs.suite.extract(nil,
|
||||
hs.suite.deriveSecret(hs.handshakeSecret, "derived", nil))
|
||||
|
||||
hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
|
||||
clientApplicationTrafficLabel, hs.transcript)
|
||||
serverSecret := hs.suite.deriveSecret(hs.masterSecret,
|
||||
serverApplicationTrafficLabel, hs.transcript)
|
||||
c.out.exportKey(EncryptionApplication, hs.suite, serverSecret)
|
||||
c.out.setTrafficSecret(hs.suite, serverSecret)
|
||||
|
||||
err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.clientHello.random, serverSecret)
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
|
||||
c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
|
||||
|
||||
// If we did not request client certificates, at this point we can
|
||||
// precompute the client finished and roll the transcript forward to send
|
||||
// session tickets in our first flight.
|
||||
if !hs.requestClientCert() {
|
||||
if err := hs.sendSessionTickets(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool {
|
||||
if hs.c.config.SessionTicketsDisabled {
|
||||
return false
|
||||
}
|
||||
|
||||
// Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9.
|
||||
for _, pskMode := range hs.clientHello.pskModes {
|
||||
if pskMode == pskModeDHE {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
||||
c := hs.c
|
||||
|
||||
hs.clientFinished = hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
|
||||
finishedMsg := &finishedMsg{
|
||||
verifyData: hs.clientFinished,
|
||||
}
|
||||
if err := transcriptMsg(finishedMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !hs.shouldSendSessionTickets() {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
|
||||
resumptionLabel, hs.transcript)
|
||||
|
||||
// Don't send session tickets when the alternative record layer is set.
|
||||
// Instead, save the resumption secret on the Conn.
|
||||
// Session tickets can then be generated by calling Conn.GetSessionTicket().
|
||||
if hs.c.extraConfig != nil && hs.c.extraConfig.AlternativeRecordLayer != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
m, err := hs.c.getSessionTicketMsg(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := c.writeHandshakeRecord(m, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
|
||||
c := hs.c
|
||||
|
||||
if !hs.requestClientCert() {
|
||||
// Make sure the connection is still being verified whether or not
|
||||
// the server requested a client certificate.
|
||||
if c.config.VerifyConnection != nil {
|
||||
if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we requested a client certificate, then the client must send a
|
||||
// certificate message. If it's empty, no CertificateVerify is sent.
|
||||
|
||||
msg, err := c.readHandshake(hs.transcript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certMsg, ok := msg.(*certificateMsgTLS13)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certMsg, msg)
|
||||
}
|
||||
|
||||
if err := c.processCertsFromClient(certMsg.certificate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.config.VerifyConnection != nil {
|
||||
if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(certMsg.certificate.Certificate) != 0 {
|
||||
// certificateVerifyMsg is included in the transcript, but not until
|
||||
// after we verify the handshake signature, since the state before
|
||||
// this message was sent is used.
|
||||
msg, err = c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
certVerify, ok := msg.(*certificateVerifyMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(certVerify, msg)
|
||||
}
|
||||
|
||||
// See RFC 8446, Section 4.4.3.
|
||||
if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: client certificate used with invalid signature algorithm")
|
||||
}
|
||||
sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: client certificate used with invalid signature algorithm")
|
||||
}
|
||||
signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
|
||||
if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
|
||||
sigHash, signed, certVerify.signature); err != nil {
|
||||
c.sendAlert(alertDecryptError)
|
||||
return errors.New("tls: invalid signature by the client certificate: " + err.Error())
|
||||
}
|
||||
|
||||
if err := transcriptMsg(certVerify, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If we waited until the client certificates to send session tickets, we
|
||||
// are ready to do it now.
|
||||
if err := hs.sendSessionTickets(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) readClientFinished() error {
|
||||
c := hs.c
|
||||
|
||||
// finishedMsg is not included in the transcript.
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
finished, ok := msg.(*finishedMsg)
|
||||
if !ok {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(finished, msg)
|
||||
}
|
||||
|
||||
if !hmac.Equal(hs.clientFinished, finished.verifyData) {
|
||||
c.sendAlert(alertDecryptError)
|
||||
return errors.New("tls: invalid client finished hash")
|
||||
}
|
||||
|
||||
c.in.exportKey(EncryptionApplication, hs.suite, hs.trafficSecret)
|
||||
c.in.setTrafficSecret(hs.suite, hs.trafficSecret)
|
||||
|
||||
return nil
|
||||
}
|
||||
357
vendor/github.com/quic-go/qtls-go1-19/key_agreement.go
generated
vendored
357
vendor/github.com/quic-go/qtls-go1-19/key_agreement.go
generated
vendored
@@ -1,357 +0,0 @@
|
||||
// Copyright 2010 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 qtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/md5"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"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")
|
||||
|
||||
// rsaKeyAgreement implements the standard TLS key agreement where the client
|
||||
// encrypts the pre-master secret to the server's public key.
|
||||
type rsaKeyAgreement struct{}
|
||||
|
||||
func (ka rsaKeyAgreement) generateServerKeyExchange(config *config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (ka rsaKeyAgreement) processClientKeyExchange(config *config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
|
||||
if len(ckx.ciphertext) < 2 {
|
||||
return nil, errClientKeyExchange
|
||||
}
|
||||
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
|
||||
if ciphertextLen != len(ckx.ciphertext)-2 {
|
||||
return nil, errClientKeyExchange
|
||||
}
|
||||
ciphertext := ckx.ciphertext[2:]
|
||||
|
||||
priv, ok := cert.PrivateKey.(crypto.Decrypter)
|
||||
if !ok {
|
||||
return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
|
||||
}
|
||||
// Perform constant time RSA PKCS #1 v1.5 decryption
|
||||
preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// We don't check the version number in the premaster secret. For one,
|
||||
// by checking it, we would leak information about the validity of the
|
||||
// encrypted pre-master secret. Secondly, it provides only a small
|
||||
// benefit against a downgrade attack and some implementations send the
|
||||
// wrong version anyway. See the discussion at the end of section
|
||||
// 7.4.7.1 of RFC 4346.
|
||||
return preMasterSecret, nil
|
||||
}
|
||||
|
||||
func (ka rsaKeyAgreement) processServerKeyExchange(config *config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
|
||||
return errors.New("tls: unexpected ServerKeyExchange")
|
||||
}
|
||||
|
||||
func (ka rsaKeyAgreement) generateClientKeyExchange(config *config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
|
||||
preMasterSecret := make([]byte, 48)
|
||||
preMasterSecret[0] = byte(clientHello.vers >> 8)
|
||||
preMasterSecret[1] = byte(clientHello.vers)
|
||||
_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
ckx := new(clientKeyExchangeMsg)
|
||||
ckx.ciphertext = make([]byte, len(encrypted)+2)
|
||||
ckx.ciphertext[0] = byte(len(encrypted) >> 8)
|
||||
ckx.ciphertext[1] = byte(len(encrypted))
|
||||
copy(ckx.ciphertext[2:], encrypted)
|
||||
return preMasterSecret, ckx, nil
|
||||
}
|
||||
|
||||
// sha1Hash calculates a SHA1 hash over the given byte slices.
|
||||
func sha1Hash(slices [][]byte) []byte {
|
||||
hsha1 := sha1.New()
|
||||
for _, slice := range slices {
|
||||
hsha1.Write(slice)
|
||||
}
|
||||
return hsha1.Sum(nil)
|
||||
}
|
||||
|
||||
// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
|
||||
// concatenation of an MD5 and SHA1 hash.
|
||||
func md5SHA1Hash(slices [][]byte) []byte {
|
||||
md5sha1 := make([]byte, md5.Size+sha1.Size)
|
||||
hmd5 := md5.New()
|
||||
for _, slice := range slices {
|
||||
hmd5.Write(slice)
|
||||
}
|
||||
copy(md5sha1, hmd5.Sum(nil))
|
||||
copy(md5sha1[md5.Size:], sha1Hash(slices))
|
||||
return md5sha1
|
||||
}
|
||||
|
||||
// hashForServerKeyExchange hashes the given slices and returns their digest
|
||||
// using the given hash function (for >= TLS 1.2) or using a default based on
|
||||
// the sigType (for earlier TLS versions). For Ed25519 signatures, which don't
|
||||
// do pre-hashing, it returns the concatenation of the slices.
|
||||
func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte {
|
||||
if sigType == signatureEd25519 {
|
||||
var signed []byte
|
||||
for _, slice := range slices {
|
||||
signed = append(signed, slice...)
|
||||
}
|
||||
return signed
|
||||
}
|
||||
if version >= VersionTLS12 {
|
||||
h := hashFunc.New()
|
||||
for _, slice := range slices {
|
||||
h.Write(slice)
|
||||
}
|
||||
digest := h.Sum(nil)
|
||||
return digest
|
||||
}
|
||||
if sigType == signatureECDSA {
|
||||
return sha1Hash(slices)
|
||||
}
|
||||
return md5SHA1Hash(slices)
|
||||
}
|
||||
|
||||
// ecdheKeyAgreement implements a TLS key agreement where the server
|
||||
// generates an ephemeral EC public/private key pair and signs it. The
|
||||
// pre-master secret is then calculated using ECDH. The signature may
|
||||
// be ECDSA, Ed25519 or RSA.
|
||||
type ecdheKeyAgreement struct {
|
||||
version uint16
|
||||
isRSA bool
|
||||
params ecdheParameters
|
||||
|
||||
// ckx and preMasterSecret are generated in processServerKeyExchange
|
||||
// and returned in generateClientKeyExchange.
|
||||
ckx *clientKeyExchangeMsg
|
||||
preMasterSecret []byte
|
||||
}
|
||||
|
||||
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
|
||||
var curveID CurveID
|
||||
for _, c := range clientHello.supportedCurves {
|
||||
if config.supportsCurve(c) {
|
||||
curveID = c
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if curveID == 0 {
|
||||
return nil, errors.New("tls: no supported elliptic curves offered")
|
||||
}
|
||||
if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
|
||||
return nil, errors.New("tls: CurvePreferences includes unsupported curve")
|
||||
}
|
||||
|
||||
params, err := generateECDHEParameters(config.rand(), curveID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ka.params = params
|
||||
|
||||
// See RFC 4492, Section 5.4.
|
||||
ecdhePublic := params.PublicKey()
|
||||
serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
|
||||
serverECDHEParams[0] = 3 // named curve
|
||||
serverECDHEParams[1] = byte(curveID >> 8)
|
||||
serverECDHEParams[2] = byte(curveID)
|
||||
serverECDHEParams[3] = byte(len(ecdhePublic))
|
||||
copy(serverECDHEParams[4:], ecdhePublic)
|
||||
|
||||
priv, ok := cert.PrivateKey.(crypto.Signer)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("tls: certificate private key of type %T does not implement crypto.Signer", cert.PrivateKey)
|
||||
}
|
||||
|
||||
var signatureAlgorithm SignatureScheme
|
||||
var sigType uint8
|
||||
var sigHash crypto.Hash
|
||||
if ka.version >= VersionTLS12 {
|
||||
signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(priv.Public())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
|
||||
return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
|
||||
}
|
||||
|
||||
signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, hello.random, serverECDHEParams)
|
||||
|
||||
signOpts := crypto.SignerOpts(sigHash)
|
||||
if sigType == signatureRSAPSS {
|
||||
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
|
||||
}
|
||||
sig, err := priv.Sign(config.rand(), signed, signOpts)
|
||||
if err != nil {
|
||||
return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
|
||||
}
|
||||
|
||||
skx := new(serverKeyExchangeMsg)
|
||||
sigAndHashLen := 0
|
||||
if ka.version >= VersionTLS12 {
|
||||
sigAndHashLen = 2
|
||||
}
|
||||
skx.key = make([]byte, len(serverECDHEParams)+sigAndHashLen+2+len(sig))
|
||||
copy(skx.key, serverECDHEParams)
|
||||
k := skx.key[len(serverECDHEParams):]
|
||||
if ka.version >= VersionTLS12 {
|
||||
k[0] = byte(signatureAlgorithm >> 8)
|
||||
k[1] = byte(signatureAlgorithm)
|
||||
k = k[2:]
|
||||
}
|
||||
k[0] = byte(len(sig) >> 8)
|
||||
k[1] = byte(len(sig))
|
||||
copy(k[2:], sig)
|
||||
|
||||
return skx, nil
|
||||
}
|
||||
|
||||
func (ka *ecdheKeyAgreement) processClientKeyExchange(config *config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
|
||||
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
|
||||
return nil, errClientKeyExchange
|
||||
}
|
||||
|
||||
preMasterSecret := ka.params.SharedKey(ckx.ciphertext[1:])
|
||||
if preMasterSecret == nil {
|
||||
return nil, errClientKeyExchange
|
||||
}
|
||||
|
||||
return preMasterSecret, nil
|
||||
}
|
||||
|
||||
func (ka *ecdheKeyAgreement) processServerKeyExchange(config *config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
|
||||
if len(skx.key) < 4 {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
if skx.key[0] != 3 { // named curve
|
||||
return errors.New("tls: server selected unsupported curve")
|
||||
}
|
||||
curveID := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
|
||||
|
||||
publicLen := int(skx.key[3])
|
||||
if publicLen+4 > len(skx.key) {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
serverECDHEParams := skx.key[:4+publicLen]
|
||||
publicKey := serverECDHEParams[4:]
|
||||
|
||||
sig := skx.key[4+publicLen:]
|
||||
if len(sig) < 2 {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
|
||||
if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
|
||||
return errors.New("tls: server selected unsupported curve")
|
||||
}
|
||||
|
||||
params, err := generateECDHEParameters(config.rand(), curveID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ka.params = params
|
||||
|
||||
ka.preMasterSecret = params.SharedKey(publicKey)
|
||||
if ka.preMasterSecret == nil {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
|
||||
ourPublicKey := params.PublicKey()
|
||||
ka.ckx = new(clientKeyExchangeMsg)
|
||||
ka.ckx.ciphertext = make([]byte, 1+len(ourPublicKey))
|
||||
ka.ckx.ciphertext[0] = byte(len(ourPublicKey))
|
||||
copy(ka.ckx.ciphertext[1:], ourPublicKey)
|
||||
|
||||
var sigType uint8
|
||||
var sigHash crypto.Hash
|
||||
if ka.version >= VersionTLS12 {
|
||||
signatureAlgorithm := SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1])
|
||||
sig = sig[2:]
|
||||
if len(sig) < 2 {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
|
||||
if !isSupportedSignatureAlgorithm(signatureAlgorithm, clientHello.supportedSignatureAlgorithms) {
|
||||
return errors.New("tls: certificate used with invalid signature algorithm")
|
||||
}
|
||||
sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(cert.PublicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
|
||||
sigLen := int(sig[0])<<8 | int(sig[1])
|
||||
if sigLen+2 != len(sig) {
|
||||
return errServerKeyExchange
|
||||
}
|
||||
sig = sig[2:]
|
||||
|
||||
signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, serverHello.random, serverECDHEParams)
|
||||
if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil {
|
||||
return errors.New("tls: invalid signature by the server certificate: " + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
|
||||
if ka.ckx == nil {
|
||||
return nil, nil, errors.New("tls: missing ServerKeyExchange message")
|
||||
}
|
||||
|
||||
return ka.preMasterSecret, ka.ckx, nil
|
||||
}
|
||||
216
vendor/github.com/quic-go/qtls-go1-19/key_schedule.go
generated
vendored
216
vendor/github.com/quic-go/qtls-go1-19/key_schedule.go
generated
vendored
@@ -1,216 +0,0 @@
|
||||
// Copyright 2018 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 qtls
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"crypto/hmac"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
|
||||
// This file contains the functions necessary to compute the TLS 1.3 key
|
||||
// schedule. See RFC 8446, Section 7.
|
||||
|
||||
const (
|
||||
resumptionBinderLabel = "res binder"
|
||||
clientHandshakeTrafficLabel = "c hs traffic"
|
||||
serverHandshakeTrafficLabel = "s hs traffic"
|
||||
clientApplicationTrafficLabel = "c ap traffic"
|
||||
serverApplicationTrafficLabel = "s ap traffic"
|
||||
exporterLabel = "exp master"
|
||||
resumptionLabel = "res master"
|
||||
trafficUpdateLabel = "traffic upd"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
b.AddBytes([]byte("tls13 "))
|
||||
b.AddBytes([]byte(label))
|
||||
})
|
||||
hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(context)
|
||||
})
|
||||
hkdfLabelBytes, err := hkdfLabel.Bytes()
|
||||
if err != nil {
|
||||
// Rather than calling BytesOrPanic, we explicitly handle this error, in
|
||||
// order to provide a reasonable error message. It should be basically
|
||||
// impossible for this to panic, and routing errors back through the
|
||||
// tree rooted in this function is quite painful. The labels are fixed
|
||||
// size, and the context is either a fixed-length computed hash, or
|
||||
// parsed from a field which has the same length limitation. As such, an
|
||||
// error here is likely to only be caused during development.
|
||||
//
|
||||
// NOTE: another reasonable approach here might be to return a
|
||||
// randomized slice if we encounter an error, which would break the
|
||||
// connection, but avoid panicking. This would perhaps be safer but
|
||||
// significantly more confusing to users.
|
||||
panic(fmt.Errorf("failed to construct HKDF label: %s", err))
|
||||
}
|
||||
out := make([]byte, length)
|
||||
n, err := hkdf.Expand(c.hash.New, secret, hkdfLabelBytes).Read(out)
|
||||
if err != nil || n != length {
|
||||
panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// 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 {
|
||||
transcript = c.hash.New()
|
||||
}
|
||||
return c.expandLabel(secret, label, transcript.Sum(nil), c.hash.Size())
|
||||
}
|
||||
|
||||
// extract implements HKDF-Extract with the cipher suite hash.
|
||||
func (c *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte {
|
||||
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,
|
||||
// according to RFC 8446, Section 7.2.
|
||||
func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte {
|
||||
return c.expandLabel(trafficSecret, trafficUpdateLabel, nil, c.hash.Size())
|
||||
}
|
||||
|
||||
// trafficKey generates traffic keys according to RFC 8446, Section 7.3.
|
||||
func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) {
|
||||
key = c.expandLabel(trafficSecret, "key", nil, c.keyLen)
|
||||
iv = c.expandLabel(trafficSecret, "iv", nil, aeadNonceLength)
|
||||
return
|
||||
}
|
||||
|
||||
// finishedHash generates the Finished verify_data or PskBinderEntry according
|
||||
// to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey
|
||||
// selection.
|
||||
func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte {
|
||||
finishedKey := c.expandLabel(baseKey, "finished", nil, c.hash.Size())
|
||||
verifyData := hmac.New(c.hash.New, finishedKey)
|
||||
verifyData.Write(transcript.Sum(nil))
|
||||
return verifyData.Sum(nil)
|
||||
}
|
||||
|
||||
// exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to
|
||||
// RFC 8446, Section 7.5.
|
||||
func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) {
|
||||
expMasterSecret := c.deriveSecret(masterSecret, exporterLabel, transcript)
|
||||
return func(label string, context []byte, length int) ([]byte, error) {
|
||||
secret := c.deriveSecret(expMasterSecret, label, nil)
|
||||
h := c.hash.New()
|
||||
h.Write(context)
|
||||
return c.expandLabel(secret, "exporter", h.Sum(nil), length), nil
|
||||
}
|
||||
}
|
||||
|
||||
// ecdheParameters implements Diffie-Hellman with either NIST curves or X25519,
|
||||
// according to RFC 8446, Section 4.2.8.2.
|
||||
type ecdheParameters interface {
|
||||
CurveID() CurveID
|
||||
PublicKey() []byte
|
||||
SharedKey(peerPublicKey []byte) []byte
|
||||
}
|
||||
|
||||
func generateECDHEParameters(rand io.Reader, curveID CurveID) (ecdheParameters, error) {
|
||||
if curveID == X25519 {
|
||||
privateKey := make([]byte, curve25519.ScalarSize)
|
||||
if _, err := io.ReadFull(rand, privateKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
publicKey, err := curve25519.X25519(privateKey, curve25519.Basepoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &x25519Parameters{privateKey: privateKey, publicKey: publicKey}, nil
|
||||
}
|
||||
|
||||
curve, ok := curveForCurveID(curveID)
|
||||
if !ok {
|
||||
return nil, errors.New("tls: internal error: unsupported curve")
|
||||
}
|
||||
|
||||
p := &nistParameters{curveID: curveID}
|
||||
var err error
|
||||
p.privateKey, p.x, p.y, err = elliptic.GenerateKey(curve, rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
|
||||
switch id {
|
||||
case CurveP256:
|
||||
return elliptic.P256(), true
|
||||
case CurveP384:
|
||||
return elliptic.P384(), true
|
||||
case CurveP521:
|
||||
return elliptic.P521(), true
|
||||
default:
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
type nistParameters struct {
|
||||
privateKey []byte
|
||||
x, y *big.Int // public key
|
||||
curveID CurveID
|
||||
}
|
||||
|
||||
func (p *nistParameters) CurveID() CurveID {
|
||||
return p.curveID
|
||||
}
|
||||
|
||||
func (p *nistParameters) PublicKey() []byte {
|
||||
curve, _ := curveForCurveID(p.curveID)
|
||||
return elliptic.Marshal(curve, p.x, p.y)
|
||||
}
|
||||
|
||||
func (p *nistParameters) SharedKey(peerPublicKey []byte) []byte {
|
||||
curve, _ := curveForCurveID(p.curveID)
|
||||
// Unmarshal also checks whether the given point is on the curve.
|
||||
x, y := elliptic.Unmarshal(curve, peerPublicKey)
|
||||
if x == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
xShared, _ := curve.ScalarMult(x, y, p.privateKey)
|
||||
sharedKey := make([]byte, (curve.Params().BitSize+7)/8)
|
||||
return xShared.FillBytes(sharedKey)
|
||||
}
|
||||
|
||||
type x25519Parameters struct {
|
||||
privateKey []byte
|
||||
publicKey []byte
|
||||
}
|
||||
|
||||
func (p *x25519Parameters) CurveID() CurveID {
|
||||
return X25519
|
||||
}
|
||||
|
||||
func (p *x25519Parameters) PublicKey() []byte {
|
||||
return p.publicKey[:]
|
||||
}
|
||||
|
||||
func (p *x25519Parameters) SharedKey(peerPublicKey []byte) []byte {
|
||||
sharedKey, err := curve25519.X25519(p.privateKey, peerPublicKey)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return sharedKey
|
||||
}
|
||||
18
vendor/github.com/quic-go/qtls-go1-19/notboring.go
generated
vendored
18
vendor/github.com/quic-go/qtls-go1-19/notboring.go
generated
vendored
@@ -1,18 +0,0 @@
|
||||
// Copyright 2022 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 qtls
|
||||
|
||||
func needFIPS() bool { return false }
|
||||
|
||||
func supportedSignatureAlgorithms() []SignatureScheme {
|
||||
return defaultSupportedSignatureAlgorithms
|
||||
}
|
||||
|
||||
func fipsMinVersion(c *config) uint16 { panic("fipsMinVersion") }
|
||||
func fipsMaxVersion(c *config) uint16 { panic("fipsMaxVersion") }
|
||||
func fipsCurvePreferences(c *config) []CurveID { panic("fipsCurvePreferences") }
|
||||
func fipsCipherSuites(c *config) []uint16 { panic("fipsCipherSuites") }
|
||||
|
||||
var fipsSupportedSignatureAlgorithms []SignatureScheme
|
||||
283
vendor/github.com/quic-go/qtls-go1-19/prf.go
generated
vendored
283
vendor/github.com/quic-go/qtls-go1-19/prf.go
generated
vendored
@@ -1,283 +0,0 @@
|
||||
// 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 qtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Split a premaster secret in two as specified in RFC 4346, Section 5.
|
||||
func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
|
||||
s1 = secret[0 : (len(secret)+1)/2]
|
||||
s2 = secret[len(secret)/2:]
|
||||
return
|
||||
}
|
||||
|
||||
// pHash implements the P_hash function, as defined in RFC 4346, Section 5.
|
||||
func pHash(result, secret, seed []byte, hash func() hash.Hash) {
|
||||
h := hmac.New(hash, secret)
|
||||
h.Write(seed)
|
||||
a := h.Sum(nil)
|
||||
|
||||
j := 0
|
||||
for j < len(result) {
|
||||
h.Reset()
|
||||
h.Write(a)
|
||||
h.Write(seed)
|
||||
b := h.Sum(nil)
|
||||
copy(result[j:], b)
|
||||
j += len(b)
|
||||
|
||||
h.Reset()
|
||||
h.Write(a)
|
||||
a = h.Sum(nil)
|
||||
}
|
||||
}
|
||||
|
||||
// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, Section 5.
|
||||
func prf10(result, secret, label, seed []byte) {
|
||||
hashSHA1 := sha1.New
|
||||
hashMD5 := md5.New
|
||||
|
||||
labelAndSeed := make([]byte, len(label)+len(seed))
|
||||
copy(labelAndSeed, label)
|
||||
copy(labelAndSeed[len(label):], seed)
|
||||
|
||||
s1, s2 := splitPreMasterSecret(secret)
|
||||
pHash(result, s1, labelAndSeed, hashMD5)
|
||||
result2 := make([]byte, len(result))
|
||||
pHash(result2, s2, labelAndSeed, hashSHA1)
|
||||
|
||||
for i, b := range result2 {
|
||||
result[i] ^= b
|
||||
}
|
||||
}
|
||||
|
||||
// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, Section 5.
|
||||
func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
|
||||
return func(result, secret, label, seed []byte) {
|
||||
labelAndSeed := make([]byte, len(label)+len(seed))
|
||||
copy(labelAndSeed, label)
|
||||
copy(labelAndSeed[len(label):], seed)
|
||||
|
||||
pHash(result, secret, labelAndSeed, hashFunc)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
masterSecretLength = 48 // Length of a master secret in TLS 1.1.
|
||||
finishedVerifyLength = 12 // Length of verify_data in a Finished message.
|
||||
)
|
||||
|
||||
var masterSecretLabel = []byte("master secret")
|
||||
var keyExpansionLabel = []byte("key expansion")
|
||||
var clientFinishedLabel = []byte("client finished")
|
||||
var serverFinishedLabel = []byte("server finished")
|
||||
|
||||
func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
|
||||
switch version {
|
||||
case VersionTLS10, VersionTLS11:
|
||||
return prf10, crypto.Hash(0)
|
||||
case VersionTLS12:
|
||||
if suite.flags&suiteSHA384 != 0 {
|
||||
return prf12(sha512.New384), crypto.SHA384
|
||||
}
|
||||
return prf12(sha256.New), crypto.SHA256
|
||||
default:
|
||||
panic("unknown version")
|
||||
}
|
||||
}
|
||||
|
||||
func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
|
||||
prf, _ := prfAndHashForVersion(version, suite)
|
||||
return prf
|
||||
}
|
||||
|
||||
// masterFromPreMasterSecret generates the master secret from the pre-master
|
||||
// secret. See RFC 5246, Section 8.1.
|
||||
func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
|
||||
seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
|
||||
seed = append(seed, clientRandom...)
|
||||
seed = append(seed, serverRandom...)
|
||||
|
||||
masterSecret := make([]byte, masterSecretLength)
|
||||
prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
|
||||
return masterSecret
|
||||
}
|
||||
|
||||
// keysFromMasterSecret generates the connection keys from the master
|
||||
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
|
||||
// RFC 2246, Section 6.3.
|
||||
func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
|
||||
seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
|
||||
seed = append(seed, serverRandom...)
|
||||
seed = append(seed, clientRandom...)
|
||||
|
||||
n := 2*macLen + 2*keyLen + 2*ivLen
|
||||
keyMaterial := make([]byte, n)
|
||||
prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed)
|
||||
clientMAC = keyMaterial[:macLen]
|
||||
keyMaterial = keyMaterial[macLen:]
|
||||
serverMAC = keyMaterial[:macLen]
|
||||
keyMaterial = keyMaterial[macLen:]
|
||||
clientKey = keyMaterial[:keyLen]
|
||||
keyMaterial = keyMaterial[keyLen:]
|
||||
serverKey = keyMaterial[:keyLen]
|
||||
keyMaterial = keyMaterial[keyLen:]
|
||||
clientIV = keyMaterial[:ivLen]
|
||||
keyMaterial = keyMaterial[ivLen:]
|
||||
serverIV = keyMaterial[:ivLen]
|
||||
return
|
||||
}
|
||||
|
||||
func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
|
||||
var buffer []byte
|
||||
if version >= VersionTLS12 {
|
||||
buffer = []byte{}
|
||||
}
|
||||
|
||||
prf, hash := prfAndHashForVersion(version, cipherSuite)
|
||||
if hash != 0 {
|
||||
return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
|
||||
}
|
||||
|
||||
return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
|
||||
}
|
||||
|
||||
// A finishedHash calculates the hash of a set of handshake messages suitable
|
||||
// for including in a Finished message.
|
||||
type finishedHash struct {
|
||||
client hash.Hash
|
||||
server hash.Hash
|
||||
|
||||
// Prior to TLS 1.2, an additional MD5 hash is required.
|
||||
clientMD5 hash.Hash
|
||||
serverMD5 hash.Hash
|
||||
|
||||
// In TLS 1.2, a full buffer is sadly required.
|
||||
buffer []byte
|
||||
|
||||
version uint16
|
||||
prf func(result, secret, label, seed []byte)
|
||||
}
|
||||
|
||||
func (h *finishedHash) Write(msg []byte) (n int, err error) {
|
||||
h.client.Write(msg)
|
||||
h.server.Write(msg)
|
||||
|
||||
if h.version < VersionTLS12 {
|
||||
h.clientMD5.Write(msg)
|
||||
h.serverMD5.Write(msg)
|
||||
}
|
||||
|
||||
if h.buffer != nil {
|
||||
h.buffer = append(h.buffer, msg...)
|
||||
}
|
||||
|
||||
return len(msg), nil
|
||||
}
|
||||
|
||||
func (h finishedHash) Sum() []byte {
|
||||
if h.version >= VersionTLS12 {
|
||||
return h.client.Sum(nil)
|
||||
}
|
||||
|
||||
out := make([]byte, 0, md5.Size+sha1.Size)
|
||||
out = h.clientMD5.Sum(out)
|
||||
return h.client.Sum(out)
|
||||
}
|
||||
|
||||
// clientSum returns the contents of the verify_data member of a client's
|
||||
// Finished message.
|
||||
func (h finishedHash) clientSum(masterSecret []byte) []byte {
|
||||
out := make([]byte, finishedVerifyLength)
|
||||
h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
|
||||
return out
|
||||
}
|
||||
|
||||
// serverSum returns the contents of the verify_data member of a server's
|
||||
// Finished message.
|
||||
func (h finishedHash) serverSum(masterSecret []byte) []byte {
|
||||
out := make([]byte, finishedVerifyLength)
|
||||
h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
|
||||
return out
|
||||
}
|
||||
|
||||
// hashForClientCertificate returns the handshake messages so far, pre-hashed if
|
||||
// necessary, suitable for signing by a TLS client certificate.
|
||||
func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) []byte {
|
||||
if (h.version >= VersionTLS12 || sigType == signatureEd25519) && h.buffer == nil {
|
||||
panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer")
|
||||
}
|
||||
|
||||
if sigType == signatureEd25519 {
|
||||
return h.buffer
|
||||
}
|
||||
|
||||
if h.version >= VersionTLS12 {
|
||||
hash := hashAlg.New()
|
||||
hash.Write(h.buffer)
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
if sigType == signatureECDSA {
|
||||
return h.server.Sum(nil)
|
||||
}
|
||||
|
||||
return h.Sum()
|
||||
}
|
||||
|
||||
// discardHandshakeBuffer is called when there is no more need to
|
||||
// buffer the entirety of the handshake messages.
|
||||
func (h *finishedHash) discardHandshakeBuffer() {
|
||||
h.buffer = nil
|
||||
}
|
||||
|
||||
// noExportedKeyingMaterial is used as a value of
|
||||
// ConnectionState.ekm when renegotiation is enabled and thus
|
||||
// we wish to fail all key-material export requests.
|
||||
func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
|
||||
return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled")
|
||||
}
|
||||
|
||||
// ekmFromMasterSecret generates exported keying material as defined in RFC 5705.
|
||||
func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) {
|
||||
return func(label string, context []byte, length int) ([]byte, error) {
|
||||
switch label {
|
||||
case "client finished", "server finished", "master secret", "key expansion":
|
||||
// These values are reserved and may not be used.
|
||||
return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label)
|
||||
}
|
||||
|
||||
seedLen := len(serverRandom) + len(clientRandom)
|
||||
if context != nil {
|
||||
seedLen += 2 + len(context)
|
||||
}
|
||||
seed := make([]byte, 0, seedLen)
|
||||
|
||||
seed = append(seed, clientRandom...)
|
||||
seed = append(seed, serverRandom...)
|
||||
|
||||
if context != nil {
|
||||
if len(context) >= 1<<16 {
|
||||
return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long")
|
||||
}
|
||||
seed = append(seed, byte(len(context)>>8), byte(len(context)))
|
||||
seed = append(seed, context...)
|
||||
}
|
||||
|
||||
keyMaterial := make([]byte, length)
|
||||
prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed)
|
||||
return keyMaterial, nil
|
||||
}
|
||||
}
|
||||
277
vendor/github.com/quic-go/qtls-go1-19/ticket.go
generated
vendored
277
vendor/github.com/quic-go/qtls-go1-19/ticket.go
generated
vendored
@@ -1,277 +0,0 @@
|
||||
// Copyright 2012 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 qtls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
)
|
||||
|
||||
// sessionState contains the information that is serialized into a session
|
||||
// ticket in order to later resume a connection.
|
||||
type sessionState struct {
|
||||
vers uint16
|
||||
cipherSuite uint16
|
||||
createdAt uint64
|
||||
masterSecret []byte // opaque master_secret<1..2^16-1>;
|
||||
// struct { opaque certificate<1..2^24-1> } Certificate;
|
||||
certificates [][]byte // Certificate certificate_list<0..2^24-1>;
|
||||
|
||||
// usedOldKey is true if the ticket from which this session came from
|
||||
// was encrypted with an older key and thus should be refreshed.
|
||||
usedOldKey bool
|
||||
}
|
||||
|
||||
func (m *sessionState) marshal() ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
b.AddUint16(m.vers)
|
||||
b.AddUint16(m.cipherSuite)
|
||||
addUint64(&b, m.createdAt)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.masterSecret)
|
||||
})
|
||||
b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, cert := range m.certificates {
|
||||
b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(cert)
|
||||
})
|
||||
}
|
||||
})
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (m *sessionState) unmarshal(data []byte) bool {
|
||||
*m = sessionState{usedOldKey: m.usedOldKey}
|
||||
s := cryptobyte.String(data)
|
||||
if ok := s.ReadUint16(&m.vers) &&
|
||||
s.ReadUint16(&m.cipherSuite) &&
|
||||
readUint64(&s, &m.createdAt) &&
|
||||
readUint16LengthPrefixed(&s, &m.masterSecret) &&
|
||||
len(m.masterSecret) != 0; !ok {
|
||||
return false
|
||||
}
|
||||
var certList cryptobyte.String
|
||||
if !s.ReadUint24LengthPrefixed(&certList) {
|
||||
return false
|
||||
}
|
||||
for !certList.Empty() {
|
||||
var cert []byte
|
||||
if !readUint24LengthPrefixed(&certList, &cert) {
|
||||
return false
|
||||
}
|
||||
m.certificates = append(m.certificates, cert)
|
||||
}
|
||||
return s.Empty()
|
||||
}
|
||||
|
||||
// sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first
|
||||
// version (revision = 0) doesn't carry any of the information needed for 0-RTT
|
||||
// validation and the nonce is always empty.
|
||||
// version (revision = 1) carries the max_early_data_size sent in the ticket.
|
||||
// version (revision = 2) carries the ALPN sent in the ticket.
|
||||
type sessionStateTLS13 struct {
|
||||
// uint8 version = 0x0304;
|
||||
// uint8 revision = 2;
|
||||
cipherSuite uint16
|
||||
createdAt uint64
|
||||
resumptionSecret []byte // opaque resumption_master_secret<1..2^8-1>;
|
||||
certificate Certificate // CertificateEntry certificate_list<0..2^24-1>;
|
||||
maxEarlyData uint32
|
||||
alpn string
|
||||
|
||||
appData []byte
|
||||
}
|
||||
|
||||
func (m *sessionStateTLS13) marshal() ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
b.AddUint16(VersionTLS13)
|
||||
b.AddUint8(2) // revision
|
||||
b.AddUint16(m.cipherSuite)
|
||||
addUint64(&b, m.createdAt)
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.resumptionSecret)
|
||||
})
|
||||
marshalCertificate(&b, m.certificate)
|
||||
b.AddUint32(m.maxEarlyData)
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(m.alpn))
|
||||
})
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.appData)
|
||||
})
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (m *sessionStateTLS13) unmarshal(data []byte) bool {
|
||||
*m = sessionStateTLS13{}
|
||||
s := cryptobyte.String(data)
|
||||
var version uint16
|
||||
var revision uint8
|
||||
var alpn []byte
|
||||
ret := s.ReadUint16(&version) &&
|
||||
version == VersionTLS13 &&
|
||||
s.ReadUint8(&revision) &&
|
||||
revision == 2 &&
|
||||
s.ReadUint16(&m.cipherSuite) &&
|
||||
readUint64(&s, &m.createdAt) &&
|
||||
readUint8LengthPrefixed(&s, &m.resumptionSecret) &&
|
||||
len(m.resumptionSecret) != 0 &&
|
||||
unmarshalCertificate(&s, &m.certificate) &&
|
||||
s.ReadUint32(&m.maxEarlyData) &&
|
||||
readUint8LengthPrefixed(&s, &alpn) &&
|
||||
readUint16LengthPrefixed(&s, &m.appData) &&
|
||||
s.Empty()
|
||||
m.alpn = string(alpn)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
|
||||
if len(c.ticketKeys) == 0 {
|
||||
return nil, errors.New("tls: internal error: session ticket keys unavailable")
|
||||
}
|
||||
|
||||
encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size)
|
||||
keyName := encrypted[:ticketKeyNameLen]
|
||||
iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
|
||||
macBytes := encrypted[len(encrypted)-sha256.Size:]
|
||||
|
||||
if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key := c.ticketKeys[0]
|
||||
copy(keyName, key.keyName[:])
|
||||
block, err := aes.NewCipher(key.aesKey[:])
|
||||
if err != nil {
|
||||
return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
|
||||
}
|
||||
cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], state)
|
||||
|
||||
mac := hmac.New(sha256.New, key.hmacKey[:])
|
||||
mac.Write(encrypted[:len(encrypted)-sha256.Size])
|
||||
mac.Sum(macBytes[:0])
|
||||
|
||||
return encrypted, nil
|
||||
}
|
||||
|
||||
func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) {
|
||||
if len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
keyName := encrypted[:ticketKeyNameLen]
|
||||
iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
|
||||
macBytes := encrypted[len(encrypted)-sha256.Size:]
|
||||
ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
|
||||
|
||||
keyIndex := -1
|
||||
for i, candidateKey := range c.ticketKeys {
|
||||
if bytes.Equal(keyName, candidateKey.keyName[:]) {
|
||||
keyIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if keyIndex == -1 {
|
||||
return nil, false
|
||||
}
|
||||
key := &c.ticketKeys[keyIndex]
|
||||
|
||||
mac := hmac.New(sha256.New, key.hmacKey[:])
|
||||
mac.Write(encrypted[:len(encrypted)-sha256.Size])
|
||||
expected := mac.Sum(nil)
|
||||
|
||||
if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher(key.aesKey[:])
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
plaintext = make([]byte, len(ciphertext))
|
||||
cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
|
||||
|
||||
return plaintext, keyIndex > 0
|
||||
}
|
||||
|
||||
func (c *Conn) getSessionTicketMsg(appData []byte) (*newSessionTicketMsgTLS13, error) {
|
||||
m := new(newSessionTicketMsgTLS13)
|
||||
|
||||
var certsFromClient [][]byte
|
||||
for _, cert := range c.peerCertificates {
|
||||
certsFromClient = append(certsFromClient, cert.Raw)
|
||||
}
|
||||
state := sessionStateTLS13{
|
||||
cipherSuite: c.cipherSuite,
|
||||
createdAt: uint64(c.config.time().Unix()),
|
||||
resumptionSecret: c.resumptionSecret,
|
||||
certificate: Certificate{
|
||||
Certificate: certsFromClient,
|
||||
OCSPStaple: c.ocspResponse,
|
||||
SignedCertificateTimestamps: c.scts,
|
||||
},
|
||||
appData: appData,
|
||||
alpn: c.clientProtocol,
|
||||
}
|
||||
if c.extraConfig != nil {
|
||||
state.maxEarlyData = c.extraConfig.MaxEarlyData
|
||||
}
|
||||
stateBytes, err := state.marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.label, err = c.encryptTicket(stateBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
|
||||
|
||||
// ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1
|
||||
// The value is not stored anywhere; we never need to check the ticket age
|
||||
// because 0-RTT is not supported.
|
||||
ageAdd := make([]byte, 4)
|
||||
_, err = c.config.rand().Read(ageAdd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.ageAdd = binary.LittleEndian.Uint32(ageAdd)
|
||||
|
||||
// ticket_nonce, which must be unique per connection, is always left at
|
||||
// zero because we only ever send one ticket per connection.
|
||||
|
||||
if c.extraConfig != nil {
|
||||
m.maxEarlyData = c.extraConfig.MaxEarlyData
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// GetSessionTicket generates a new session ticket.
|
||||
// It should only be called after the handshake completes.
|
||||
// It can only be used for servers, and only if the alternative record layer is set.
|
||||
// The ticket may be nil if config.SessionTicketsDisabled is set,
|
||||
// or if the client isn't able to receive session tickets.
|
||||
func (c *Conn) GetSessionTicket(appData []byte) ([]byte, error) {
|
||||
if c.isClient || !c.handshakeComplete() || c.extraConfig == nil || c.extraConfig.AlternativeRecordLayer == nil {
|
||||
return nil, errors.New("GetSessionTicket is only valid for servers after completion of the handshake, and if an alternative record layer is set.")
|
||||
}
|
||||
if c.config.SessionTicketsDisabled {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
m, err := c.getSessionTicketMsg(appData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m.marshal()
|
||||
}
|
||||
362
vendor/github.com/quic-go/qtls-go1-19/tls.go
generated
vendored
362
vendor/github.com/quic-go/qtls-go1-19/tls.go
generated
vendored
@@ -1,362 +0,0 @@
|
||||
// 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 qtls partially implements TLS 1.2, as specified in RFC 5246,
|
||||
// and TLS 1.3, as specified in RFC 8446.
|
||||
package qtls
|
||||
|
||||
// BUG(agl): The crypto/tls package only implements some countermeasures
|
||||
// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
|
||||
// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
|
||||
// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Server returns a new TLS server side connection
|
||||
// using conn as the underlying transport.
|
||||
// The configuration config must be non-nil and must include
|
||||
// at least one certificate or else set GetCertificate.
|
||||
func Server(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
c := &Conn{
|
||||
conn: conn,
|
||||
config: fromConfig(config),
|
||||
extraConfig: extraConfig,
|
||||
}
|
||||
c.handshakeFn = c.serverHandshake
|
||||
return c
|
||||
}
|
||||
|
||||
// Client returns a new TLS client side connection
|
||||
// using conn as the underlying transport.
|
||||
// The config cannot be nil: users must set either ServerName or
|
||||
// InsecureSkipVerify in the config.
|
||||
func Client(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
c := &Conn{
|
||||
conn: conn,
|
||||
config: fromConfig(config),
|
||||
extraConfig: extraConfig,
|
||||
isClient: true,
|
||||
}
|
||||
c.handshakeFn = c.clientHandshake
|
||||
return c
|
||||
}
|
||||
|
||||
// A listener implements a network listener (net.Listener) for TLS connections.
|
||||
type listener struct {
|
||||
net.Listener
|
||||
config *Config
|
||||
extraConfig *ExtraConfig
|
||||
}
|
||||
|
||||
// Accept waits for and returns the next incoming TLS connection.
|
||||
// The returned connection is of type *Conn.
|
||||
func (l *listener) Accept() (net.Conn, error) {
|
||||
c, err := l.Listener.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Server(c, l.config, l.extraConfig), nil
|
||||
}
|
||||
|
||||
// NewListener creates a Listener which accepts connections from an inner
|
||||
// Listener and wraps each connection with Server.
|
||||
// The configuration config must be non-nil and must include
|
||||
// at least one certificate or else set GetCertificate.
|
||||
func NewListener(inner net.Listener, config *Config, extraConfig *ExtraConfig) net.Listener {
|
||||
l := new(listener)
|
||||
l.Listener = inner
|
||||
l.config = config
|
||||
l.extraConfig = extraConfig
|
||||
return l
|
||||
}
|
||||
|
||||
// Listen creates a TLS listener accepting connections on the
|
||||
// given network address using net.Listen.
|
||||
// The configuration config must be non-nil and must include
|
||||
// at least one certificate or else set GetCertificate.
|
||||
func Listen(network, laddr string, config *Config, extraConfig *ExtraConfig) (net.Listener, error) {
|
||||
if config == nil || len(config.Certificates) == 0 &&
|
||||
config.GetCertificate == nil && config.GetConfigForClient == nil {
|
||||
return nil, errors.New("tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config")
|
||||
}
|
||||
l, err := net.Listen(network, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewListener(l, config, extraConfig), nil
|
||||
}
|
||||
|
||||
type timeoutError struct{}
|
||||
|
||||
func (timeoutError) Error() string { return "tls: DialWithDialer timed out" }
|
||||
func (timeoutError) Timeout() bool { return true }
|
||||
func (timeoutError) Temporary() bool { return true }
|
||||
|
||||
// DialWithDialer connects to the given network address using dialer.Dial and
|
||||
// then initiates a TLS handshake, returning the resulting TLS connection. Any
|
||||
// timeout or deadline given in the dialer apply to connection and TLS
|
||||
// handshake as a whole.
|
||||
//
|
||||
// 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) {
|
||||
if netDialer.Timeout != 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
if !netDialer.Deadline.IsZero() {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
rawConn, err := netDialer.DialContext(ctx, network, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
colonPos := strings.LastIndex(addr, ":")
|
||||
if colonPos == -1 {
|
||||
colonPos = len(addr)
|
||||
}
|
||||
hostname := addr[:colonPos]
|
||||
|
||||
if config == nil {
|
||||
config = defaultConfig()
|
||||
}
|
||||
// If no ServerName is set, infer the ServerName
|
||||
// from the hostname we're connecting to.
|
||||
if config.ServerName == "" {
|
||||
// Make a copy to avoid polluting argument or default.
|
||||
c := config.Clone()
|
||||
c.ServerName = hostname
|
||||
config = c
|
||||
}
|
||||
|
||||
conn := Client(rawConn, config, extraConfig)
|
||||
if err := conn.HandshakeContext(ctx); err != nil {
|
||||
rawConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Dial connects to the given network address using net.Dial
|
||||
// and then initiates a TLS handshake, returning the resulting
|
||||
// TLS connection.
|
||||
// Dial interprets a nil configuration as equivalent to
|
||||
// the zero configuration; see the documentation of Config
|
||||
// for the defaults.
|
||||
func Dial(network, addr string, config *Config, extraConfig *ExtraConfig) (*Conn, error) {
|
||||
return DialWithDialer(new(net.Dialer), network, addr, config, extraConfig)
|
||||
}
|
||||
|
||||
// Dialer dials TLS connections given a configuration and a Dialer for the
|
||||
// underlying connection.
|
||||
type Dialer struct {
|
||||
// NetDialer is the optional dialer to use for the TLS connections'
|
||||
// underlying TCP connections.
|
||||
// A nil NetDialer is equivalent to the net.Dialer zero value.
|
||||
NetDialer *net.Dialer
|
||||
|
||||
// Config is the TLS configuration to use for new connections.
|
||||
// A nil configuration is equivalent to the zero
|
||||
// configuration; see the documentation of Config for the
|
||||
// defaults.
|
||||
Config *Config
|
||||
|
||||
ExtraConfig *ExtraConfig
|
||||
}
|
||||
|
||||
// Dial connects to the given network address and initiates a TLS
|
||||
// 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)
|
||||
}
|
||||
|
||||
func (d *Dialer) netDialer() *net.Dialer {
|
||||
if d.NetDialer != nil {
|
||||
return d.NetDialer
|
||||
}
|
||||
return new(net.Dialer)
|
||||
}
|
||||
|
||||
// DialContext connects to the given network address and initiates a TLS
|
||||
// handshake, returning the resulting TLS connection.
|
||||
//
|
||||
// The provided Context must be non-nil. If the context expires before
|
||||
// the connection is complete, an error is returned. Once successfully
|
||||
// connected, any expiration of the context will not affect the
|
||||
// connection.
|
||||
//
|
||||
// The returned Conn, if any, will always be of type *Conn.
|
||||
func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
c, err := dial(ctx, d.netDialer(), network, addr, d.Config, d.ExtraConfig)
|
||||
if err != nil {
|
||||
// Don't return c (a typed nil) in an interface.
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// LoadX509KeyPair reads and parses a public/private key pair from a pair
|
||||
// of files. The files must contain PEM encoded data. The certificate file
|
||||
// may contain intermediate certificates following the leaf certificate to
|
||||
// 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 := os.ReadFile(certFile)
|
||||
if err != nil {
|
||||
return Certificate{}, err
|
||||
}
|
||||
keyPEMBlock, err := os.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
return Certificate{}, err
|
||||
}
|
||||
return X509KeyPair(certPEMBlock, keyPEMBlock)
|
||||
}
|
||||
|
||||
// X509KeyPair parses a public/private key pair from a pair of
|
||||
// PEM encoded data. On successful return, Certificate.Leaf will be nil because
|
||||
// the parsed form of the certificate is not retained.
|
||||
func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
|
||||
fail := func(err error) (Certificate, error) { return Certificate{}, err }
|
||||
|
||||
var cert Certificate
|
||||
var skippedBlockTypes []string
|
||||
for {
|
||||
var certDERBlock *pem.Block
|
||||
certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
|
||||
if certDERBlock == nil {
|
||||
break
|
||||
}
|
||||
if certDERBlock.Type == "CERTIFICATE" {
|
||||
cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
|
||||
} else {
|
||||
skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cert.Certificate) == 0 {
|
||||
if len(skippedBlockTypes) == 0 {
|
||||
return fail(errors.New("tls: failed to find any PEM data in certificate input"))
|
||||
}
|
||||
if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
|
||||
return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
|
||||
}
|
||||
return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
|
||||
}
|
||||
|
||||
skippedBlockTypes = skippedBlockTypes[:0]
|
||||
var keyDERBlock *pem.Block
|
||||
for {
|
||||
keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
|
||||
if keyDERBlock == nil {
|
||||
if len(skippedBlockTypes) == 0 {
|
||||
return fail(errors.New("tls: failed to find any PEM data in key input"))
|
||||
}
|
||||
if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
|
||||
return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key"))
|
||||
}
|
||||
return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
|
||||
}
|
||||
if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
|
||||
break
|
||||
}
|
||||
skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type)
|
||||
}
|
||||
|
||||
// We don't need to parse the public key for TLS, but we so do anyway
|
||||
// to check that it looks sane and matches the private key.
|
||||
x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
|
||||
cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
|
||||
switch pub := x509Cert.PublicKey.(type) {
|
||||
case *rsa.PublicKey:
|
||||
priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return fail(errors.New("tls: private key type does not match public key type"))
|
||||
}
|
||||
if pub.N.Cmp(priv.N) != 0 {
|
||||
return fail(errors.New("tls: private key does not match public key"))
|
||||
}
|
||||
case *ecdsa.PublicKey:
|
||||
priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
|
||||
if !ok {
|
||||
return fail(errors.New("tls: private key type does not match public key type"))
|
||||
}
|
||||
if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
|
||||
return fail(errors.New("tls: private key does not match public key"))
|
||||
}
|
||||
case ed25519.PublicKey:
|
||||
priv, ok := cert.PrivateKey.(ed25519.PrivateKey)
|
||||
if !ok {
|
||||
return fail(errors.New("tls: private key type does not match public key type"))
|
||||
}
|
||||
if !bytes.Equal(priv.Public().(ed25519.PublicKey), pub) {
|
||||
return fail(errors.New("tls: private key does not match public key"))
|
||||
}
|
||||
default:
|
||||
return fail(errors.New("tls: unknown public key algorithm"))
|
||||
}
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
|
||||
// PKCS #1 private keys by default, while OpenSSL 1.0.0 generates PKCS #8 keys.
|
||||
// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
|
||||
func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
|
||||
if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
|
||||
return key, nil
|
||||
}
|
||||
if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
|
||||
switch key := key.(type) {
|
||||
case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
|
||||
return key, nil
|
||||
default:
|
||||
return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
|
||||
}
|
||||
}
|
||||
if key, err := x509.ParseECPrivateKey(der); err == nil {
|
||||
return key, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("tls: failed to parse private key")
|
||||
}
|
||||
96
vendor/github.com/quic-go/qtls-go1-19/unsafe.go
generated
vendored
96
vendor/github.com/quic-go/qtls-go1-19/unsafe.go
generated
vendored
@@ -1,96 +0,0 @@
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if !structsEqual(&tls.ConnectionState{}, &connectionState{}) {
|
||||
panic("qtls.ConnectionState doesn't match")
|
||||
}
|
||||
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")
|
||||
}
|
||||
if !structsEqual(&tls.ClientHelloInfo{}, &clientHelloInfo{}) {
|
||||
panic("qtls.ClientHelloInfo doesn't match")
|
||||
}
|
||||
}
|
||||
|
||||
func toConnectionState(c connectionState) ConnectionState {
|
||||
return *(*ConnectionState)(unsafe.Pointer(&c))
|
||||
}
|
||||
|
||||
func toClientSessionState(s *clientSessionState) *ClientSessionState {
|
||||
return (*ClientSessionState)(unsafe.Pointer(s))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
func fromConfig(c *Config) *config {
|
||||
return (*config)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func toClientHelloInfo(chi *clientHelloInfo) *ClientHelloInfo {
|
||||
return (*ClientHelloInfo)(unsafe.Pointer(chi))
|
||||
}
|
||||
|
||||
func structsEqual(a, b interface{}) bool {
|
||||
return compare(reflect.ValueOf(a), reflect.ValueOf(b))
|
||||
}
|
||||
|
||||
func compare(a, b reflect.Value) bool {
|
||||
sa := a.Elem()
|
||||
sb := b.Elem()
|
||||
if sa.NumField() != sb.NumField() {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < sa.NumField(); i++ {
|
||||
fa := sa.Type().Field(i)
|
||||
fb := sb.Type().Field(i)
|
||||
if !reflect.DeepEqual(fa.Index, fb.Index) || fa.Name != fb.Name || fa.Anonymous != fb.Anonymous || fa.Offset != fb.Offset || !reflect.DeepEqual(fa.Type, fb.Type) {
|
||||
if fa.Type.Kind() != fb.Type.Kind() {
|
||||
return false
|
||||
}
|
||||
if fa.Type.Kind() == reflect.Slice {
|
||||
if !compareStruct(fa.Type.Elem(), fb.Type.Elem()) {
|
||||
return false
|
||||
}
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func compareStruct(a, b reflect.Type) bool {
|
||||
if a.NumField() != b.NumField() {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < a.NumField(); i++ {
|
||||
fa := a.Field(i)
|
||||
fb := b.Field(i)
|
||||
if !reflect.DeepEqual(fa.Index, fb.Index) || fa.Name != fb.Name || fa.Anonymous != fb.Anonymous || fa.Offset != fb.Offset || !reflect.DeepEqual(fa.Type, fb.Type) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
13
vendor/github.com/quic-go/qtls-go1-20/alert.go
generated
vendored
13
vendor/github.com/quic-go/qtls-go1-20/alert.go
generated
vendored
@@ -6,10 +6,17 @@ package qtls
|
||||
|
||||
import "strconv"
|
||||
|
||||
type alert uint8
|
||||
// An AlertError is a TLS alert.
|
||||
//
|
||||
// When using a QUIC transport, QUICConn methods will return an error
|
||||
// which wraps AlertError rather than sending a TLS alert.
|
||||
type AlertError uint8
|
||||
|
||||
// Alert is a TLS alert
|
||||
type Alert = alert
|
||||
func (e AlertError) Error() string {
|
||||
return alert(e).String()
|
||||
}
|
||||
|
||||
type alert uint8
|
||||
|
||||
const (
|
||||
// alert level
|
||||
|
||||
30
vendor/github.com/quic-go/qtls-go1-20/cipher_suites.go
generated
vendored
30
vendor/github.com/quic-go/qtls-go1-20/cipher_suites.go
generated
vendored
@@ -15,8 +15,10 @@ import (
|
||||
"crypto/sha256"
|
||||
"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
|
||||
@@ -195,17 +197,6 @@ type cipherSuiteTLS13 struct {
|
||||
hash crypto.Hash
|
||||
}
|
||||
|
||||
type CipherSuiteTLS13 struct {
|
||||
ID uint16
|
||||
KeyLen int
|
||||
Hash crypto.Hash
|
||||
AEAD func(key, fixedNonce []byte) cipher.AEAD
|
||||
}
|
||||
|
||||
func (c *CipherSuiteTLS13) IVLen() int {
|
||||
return aeadNonceLength
|
||||
}
|
||||
|
||||
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},
|
||||
@@ -362,6 +353,18 @@ var defaultCipherSuitesTLS13NoAES = []uint16{
|
||||
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,
|
||||
@@ -519,11 +522,6 @@ func aeadAESGCM(key, noncePrefix []byte) aead {
|
||||
return ret
|
||||
}
|
||||
|
||||
// AEADAESGCMTLS13 creates a new AES-GCM AEAD for TLS 1.3
|
||||
func AEADAESGCMTLS13(key, fixedNonce []byte) cipher.AEAD {
|
||||
return aeadAESGCMTLS13(key, fixedNonce)
|
||||
}
|
||||
|
||||
func aeadAESGCMTLS13(key, nonceMask []byte) aead {
|
||||
if len(nonceMask) != aeadNonceLength {
|
||||
panic("tls: internal error: wrong nonce length")
|
||||
|
||||
106
vendor/github.com/quic-go/qtls-go1-20/common.go
generated
vendored
106
vendor/github.com/quic-go/qtls-go1-20/common.go
generated
vendored
@@ -82,11 +82,6 @@ const (
|
||||
compressionNone uint8 = 0
|
||||
)
|
||||
|
||||
type Extension struct {
|
||||
Type uint16
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// TLS extension numbers
|
||||
const (
|
||||
extensionServerName uint16 = 0
|
||||
@@ -105,6 +100,7 @@ const (
|
||||
extensionCertificateAuthorities uint16 = 47
|
||||
extensionSignatureAlgorithmsCert uint16 = 50
|
||||
extensionKeyShare uint16 = 51
|
||||
extensionQUICTransportParameters uint16 = 57
|
||||
extensionRenegotiationInfo uint16 = 0xff01
|
||||
)
|
||||
|
||||
@@ -113,14 +109,6 @@ const (
|
||||
scsvRenegotiation uint16 = 0x00ff
|
||||
)
|
||||
|
||||
type EncryptionLevel uint8
|
||||
|
||||
const (
|
||||
EncryptionHandshake EncryptionLevel = iota
|
||||
Encryption0RTT
|
||||
EncryptionApplication
|
||||
)
|
||||
|
||||
// CurveID is a tls.CurveID
|
||||
type CurveID = tls.CurveID
|
||||
|
||||
@@ -294,12 +282,6 @@ type connectionState struct {
|
||||
ekm func(label string, context []byte, length int) ([]byte, error)
|
||||
}
|
||||
|
||||
type ConnectionStateWith0RTT struct {
|
||||
ConnectionState
|
||||
|
||||
Used0RTT bool // true if 0-RTT was both offered and accepted
|
||||
}
|
||||
|
||||
// ClientAuthType is tls.ClientAuthType
|
||||
type ClientAuthType = tls.ClientAuthType
|
||||
|
||||
@@ -349,8 +331,6 @@ 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/quic-go/qtls-go1-20 ClientSessionCache"
|
||||
type ClientSessionCache = tls.ClientSessionCache
|
||||
|
||||
// SignatureScheme is a tls.SignatureScheme
|
||||
@@ -736,64 +716,22 @@ type config struct {
|
||||
autoSessionTicketKeys []ticketKey
|
||||
}
|
||||
|
||||
// A RecordLayer handles encrypting and decrypting of TLS messages.
|
||||
type RecordLayer interface {
|
||||
SetReadKey(encLevel EncryptionLevel, suite *CipherSuiteTLS13, trafficSecret []byte)
|
||||
SetWriteKey(encLevel EncryptionLevel, suite *CipherSuiteTLS13, trafficSecret []byte)
|
||||
ReadHandshakeMessage() ([]byte, error)
|
||||
WriteRecord([]byte) (int, error)
|
||||
SendAlert(uint8)
|
||||
}
|
||||
|
||||
type ExtraConfig struct {
|
||||
// GetExtensions, if not nil, is called before a message that allows
|
||||
// sending of extensions is sent.
|
||||
// Currently only implemented for the ClientHello message (for the client)
|
||||
// and for the EncryptedExtensions message (for the server).
|
||||
// Only valid for TLS 1.3.
|
||||
GetExtensions func(handshakeMessageType uint8) []Extension
|
||||
|
||||
// ReceivedExtensions, if not nil, is called when a message that allows the
|
||||
// inclusion of extensions is received.
|
||||
// It is called with an empty slice of extensions, if the message didn't
|
||||
// contain any extensions.
|
||||
// Currently only implemented for the ClientHello message (sent by the
|
||||
// client) and for the EncryptedExtensions message (sent by the server).
|
||||
// Only valid for TLS 1.3.
|
||||
ReceivedExtensions func(handshakeMessageType uint8, exts []Extension)
|
||||
|
||||
// AlternativeRecordLayer is used by QUIC
|
||||
AlternativeRecordLayer RecordLayer
|
||||
|
||||
// Enforce the selection of a supported application protocol.
|
||||
// Only works for TLS 1.3.
|
||||
// If enabled, client and server have to agree on an application protocol.
|
||||
// Otherwise, connection establishment fails.
|
||||
EnforceNextProtoSelection bool
|
||||
|
||||
// If MaxEarlyData is greater than 0, the client will be allowed to send early
|
||||
// data when resuming a session.
|
||||
// Requires the AlternativeRecordLayer to be set.
|
||||
// If Enable0RTT is enabled, the client will be allowed to send early data when resuming a session.
|
||||
//
|
||||
// It has no meaning on the client.
|
||||
MaxEarlyData uint32
|
||||
Enable0RTT bool
|
||||
|
||||
// GetAppDataForSessionTicket requests application data to be sent with a session ticket.
|
||||
//
|
||||
// It has no meaning on the client.
|
||||
GetAppDataForSessionTicket func() []byte
|
||||
|
||||
// The Accept0RTT callback is called when the client offers 0-RTT.
|
||||
// The server then has to decide if it wants to accept or reject 0-RTT.
|
||||
// It is only used for servers.
|
||||
Accept0RTT func(appData []byte) bool
|
||||
|
||||
// 0RTTRejected is called when the server rejectes 0-RTT.
|
||||
// It is only used for clients.
|
||||
Rejected0RTT func()
|
||||
|
||||
// If set, the client will export the 0-RTT key when resuming a session that
|
||||
// allows sending of early data.
|
||||
// Requires the AlternativeRecordLayer to be set.
|
||||
//
|
||||
// It has no meaning to the server.
|
||||
Enable0RTT bool
|
||||
|
||||
// Is called when the client saves a session ticket to the session ticket.
|
||||
// This gives the application the opportunity to save some data along with the ticket,
|
||||
// which can be restored when the session ticket is used.
|
||||
@@ -801,29 +739,20 @@ type ExtraConfig struct {
|
||||
|
||||
// Is called when the client uses a session ticket.
|
||||
// Restores the application data that was saved earlier on GetAppDataForSessionTicket.
|
||||
SetAppDataFromSessionState func([]byte)
|
||||
SetAppDataFromSessionState func([]byte) (allowEarlyData bool)
|
||||
}
|
||||
|
||||
// Clone clones.
|
||||
func (c *ExtraConfig) Clone() *ExtraConfig {
|
||||
return &ExtraConfig{
|
||||
GetExtensions: c.GetExtensions,
|
||||
ReceivedExtensions: c.ReceivedExtensions,
|
||||
AlternativeRecordLayer: c.AlternativeRecordLayer,
|
||||
EnforceNextProtoSelection: c.EnforceNextProtoSelection,
|
||||
MaxEarlyData: c.MaxEarlyData,
|
||||
Enable0RTT: c.Enable0RTT,
|
||||
GetAppDataForSessionTicket: c.GetAppDataForSessionTicket,
|
||||
Accept0RTT: c.Accept0RTT,
|
||||
Rejected0RTT: c.Rejected0RTT,
|
||||
GetAppDataForSessionState: c.GetAppDataForSessionState,
|
||||
SetAppDataFromSessionState: c.SetAppDataFromSessionState,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ExtraConfig) usesAlternativeRecordLayer() bool {
|
||||
return c != nil && c.AlternativeRecordLayer != nil
|
||||
}
|
||||
|
||||
const (
|
||||
// ticketKeyNameLen is the number of bytes of identifier that is prepended to
|
||||
// an encrypted session ticket in order to identify the key used to encrypt it.
|
||||
@@ -1384,7 +1313,6 @@ func (c *config) BuildNameToCertificate() {
|
||||
|
||||
const (
|
||||
keyLogLabelTLS12 = "CLIENT_RANDOM"
|
||||
keyLogLabelEarlyTraffic = "CLIENT_EARLY_TRAFFIC_SECRET"
|
||||
keyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
|
||||
keyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET"
|
||||
keyLogLabelClientTraffic = "CLIENT_TRAFFIC_SECRET_0"
|
||||
@@ -1523,16 +1451,4 @@ func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlg
|
||||
}
|
||||
|
||||
// CertificateVerificationError is returned when certificate verification fails during the handshake.
|
||||
type CertificateVerificationError struct {
|
||||
// UnverifiedCertificates and its contents should not be modified.
|
||||
UnverifiedCertificates []*x509.Certificate
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e *CertificateVerificationError) Error() string {
|
||||
return fmt.Sprintf("tls: failed to verify certificate: %s", e.Err)
|
||||
}
|
||||
|
||||
func (e *CertificateVerificationError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
type CertificateVerificationError = tls.CertificateVerificationError
|
||||
|
||||
225
vendor/github.com/quic-go/qtls-go1-20/conn.go
generated
vendored
225
vendor/github.com/quic-go/qtls-go1-20/conn.go
generated
vendored
@@ -29,6 +29,7 @@ type Conn struct {
|
||||
conn net.Conn
|
||||
isClient bool
|
||||
handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake
|
||||
quic *quicState // nil for non-QUIC connections
|
||||
|
||||
// isHandshakeComplete is true if the connection is currently transferring
|
||||
// application data (i.e. is not currently processing a handshake).
|
||||
@@ -40,11 +41,10 @@ type Conn struct {
|
||||
vers uint16 // TLS version
|
||||
haveVers bool // version has been negotiated
|
||||
config *config // configuration passed to constructor
|
||||
extraConfig *ExtraConfig
|
||||
// handshakes counts the number of handshakes performed on the
|
||||
// connection so far. If renegotiation is disabled then this is either
|
||||
// zero or one.
|
||||
extraConfig *ExtraConfig
|
||||
|
||||
handshakes int
|
||||
didResume bool // whether this connection was a session resumption
|
||||
cipherSuite uint16
|
||||
@@ -65,13 +65,8 @@ type Conn struct {
|
||||
secureRenegotiation bool
|
||||
// ekm is a closure for exporting keying material.
|
||||
ekm func(label string, context []byte, length int) ([]byte, error)
|
||||
// For the client:
|
||||
// resumptionSecret is the resumption_master_secret for handling
|
||||
// NewSessionTicket messages. nil if config.SessionTicketsDisabled.
|
||||
// For the server:
|
||||
// resumptionSecret is the resumption_master_secret for generating
|
||||
// NewSessionTicket messages. Only used when the alternative record
|
||||
// layer is set. nil if config.SessionTicketsDisabled.
|
||||
// or sending NewSessionTicket messages.
|
||||
resumptionSecret []byte
|
||||
|
||||
// ticketKeys is the set of active session ticket keys for this
|
||||
@@ -123,12 +118,7 @@ type Conn struct {
|
||||
// the rest of the bits are the number of goroutines in Conn.Write.
|
||||
activeCall atomic.Int32
|
||||
|
||||
used0RTT bool
|
||||
|
||||
tmp [16]byte
|
||||
|
||||
connStateMutex sync.Mutex
|
||||
connState ConnectionStateWith0RTT
|
||||
}
|
||||
|
||||
// Access to net.Conn methods.
|
||||
@@ -188,9 +178,8 @@ type halfConn struct {
|
||||
nextCipher any // next encryption state
|
||||
nextMac hash.Hash // next MAC algorithm
|
||||
|
||||
trafficSecret []byte // current TLS 1.3 traffic secret
|
||||
|
||||
setKeyCallback func(encLevel EncryptionLevel, suite *CipherSuiteTLS13, trafficSecret []byte)
|
||||
level QUICEncryptionLevel // current QUIC encryption level
|
||||
trafficSecret []byte // current TLS 1.3 traffic secret
|
||||
}
|
||||
|
||||
type permanentError struct {
|
||||
@@ -235,20 +224,9 @@ func (hc *halfConn) changeCipherSpec() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hc *halfConn) exportKey(encLevel EncryptionLevel, suite *cipherSuiteTLS13, trafficSecret []byte) {
|
||||
if hc.setKeyCallback != nil {
|
||||
s := &CipherSuiteTLS13{
|
||||
ID: suite.id,
|
||||
KeyLen: suite.keyLen,
|
||||
Hash: suite.hash,
|
||||
AEAD: func(key, fixedNonce []byte) cipher.AEAD { return suite.aead(key, fixedNonce) },
|
||||
}
|
||||
hc.setKeyCallback(encLevel, s, trafficSecret)
|
||||
}
|
||||
}
|
||||
|
||||
func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, secret []byte) {
|
||||
func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) {
|
||||
hc.trafficSecret = secret
|
||||
hc.level = level
|
||||
key, iv := suite.trafficKey(secret)
|
||||
hc.cipher = suite.aead(key, iv)
|
||||
for i := range hc.seq {
|
||||
@@ -481,13 +459,6 @@ func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
|
||||
return plaintext, typ, nil
|
||||
}
|
||||
|
||||
func (c *Conn) setAlternativeRecordLayer() {
|
||||
if c.extraConfig != nil && c.extraConfig.AlternativeRecordLayer != nil {
|
||||
c.in.setKeyCallback = c.extraConfig.AlternativeRecordLayer.SetReadKey
|
||||
c.out.setKeyCallback = c.extraConfig.AlternativeRecordLayer.SetWriteKey
|
||||
}
|
||||
}
|
||||
|
||||
// sliceForAppend extends the input slice by n bytes. head is the full extended
|
||||
// slice, while tail is the appended part. If the original slice has sufficient
|
||||
// capacity no allocation is performed.
|
||||
@@ -646,6 +617,10 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
|
||||
}
|
||||
c.input.Reset(nil)
|
||||
|
||||
if c.quic != nil {
|
||||
return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with QUIC transport"))
|
||||
}
|
||||
|
||||
// Read header, payload.
|
||||
if err := c.readFromUntil(c.conn, recordHeaderLen); err != nil {
|
||||
// RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify
|
||||
@@ -729,6 +704,9 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
|
||||
case recordTypeAlert:
|
||||
if c.quic != nil {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
}
|
||||
if len(data) != 2 {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
|
||||
}
|
||||
@@ -846,6 +824,9 @@ func (c *Conn) readFromUntil(r io.Reader, n int) error {
|
||||
|
||||
// sendAlert sends a TLS alert message.
|
||||
func (c *Conn) sendAlertLocked(err alert) error {
|
||||
if c.quic != nil {
|
||||
return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
|
||||
}
|
||||
switch err {
|
||||
case alertNoRenegotiation, alertCloseNotify:
|
||||
c.tmp[0] = alertLevelWarning
|
||||
@@ -865,11 +846,6 @@ func (c *Conn) sendAlertLocked(err alert) error {
|
||||
|
||||
// sendAlert sends a TLS alert message.
|
||||
func (c *Conn) sendAlert(err alert) error {
|
||||
if c.extraConfig != nil && c.extraConfig.AlternativeRecordLayer != nil {
|
||||
c.extraConfig.AlternativeRecordLayer.SendAlert(uint8(err))
|
||||
return &net.OpError{Op: "local error", Err: err}
|
||||
}
|
||||
|
||||
c.out.Lock()
|
||||
defer c.out.Unlock()
|
||||
return c.sendAlertLocked(err)
|
||||
@@ -985,6 +961,19 @@ var outBufPool = sync.Pool{
|
||||
// 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) {
|
||||
if c.quic != nil {
|
||||
if typ != recordTypeHandshake {
|
||||
return 0, errors.New("tls: internal error: sending non-handshake message to QUIC transport")
|
||||
}
|
||||
c.quicWriteCryptoData(c.out.level, data)
|
||||
if !c.buffering {
|
||||
if _, err := c.flush(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
outBufPtr := outBufPool.Get().(*[]byte)
|
||||
outBuf := *outBufPtr
|
||||
defer func() {
|
||||
@@ -1046,69 +1035,63 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
|
||||
// the record layer state. If transcript is non-nil the marshalled message is
|
||||
// written to it.
|
||||
func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) {
|
||||
c.out.Lock()
|
||||
defer c.out.Unlock()
|
||||
|
||||
data, err := msg.marshal()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
c.out.Lock()
|
||||
defer c.out.Unlock()
|
||||
|
||||
if transcript != nil {
|
||||
transcript.Write(data)
|
||||
}
|
||||
|
||||
if c.extraConfig != nil && c.extraConfig.AlternativeRecordLayer != nil {
|
||||
return c.extraConfig.AlternativeRecordLayer.WriteRecord(data)
|
||||
}
|
||||
|
||||
return c.writeRecordLocked(recordTypeHandshake, data)
|
||||
}
|
||||
|
||||
// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and
|
||||
// updates the record layer state.
|
||||
func (c *Conn) writeChangeCipherRecord() error {
|
||||
if c.extraConfig != nil && c.extraConfig.AlternativeRecordLayer != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.out.Lock()
|
||||
defer c.out.Unlock()
|
||||
_, err := c.writeRecordLocked(recordTypeChangeCipherSpec, []byte{1})
|
||||
return err
|
||||
}
|
||||
|
||||
// readHandshakeBytes reads handshake data until c.hand contains at least n bytes.
|
||||
func (c *Conn) readHandshakeBytes(n int) error {
|
||||
if c.quic != nil {
|
||||
return c.quicReadHandshakeBytes(n)
|
||||
}
|
||||
for c.hand.Len() < n {
|
||||
if err := c.readRecord(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readHandshake reads the next handshake message from
|
||||
// the record layer. If transcript is non-nil, the message
|
||||
// is written to the passed transcriptHash.
|
||||
func (c *Conn) readHandshake(transcript transcriptHash) (any, error) {
|
||||
var data []byte
|
||||
if c.extraConfig != nil && c.extraConfig.AlternativeRecordLayer != nil {
|
||||
var err error
|
||||
data, err = c.extraConfig.AlternativeRecordLayer.ReadHandshakeMessage()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
for c.hand.Len() < 4 {
|
||||
if err := c.readRecord(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
data = c.hand.Bytes()
|
||||
n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
|
||||
if n > maxHandshake {
|
||||
c.sendAlertLocked(alertInternalError)
|
||||
return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake))
|
||||
}
|
||||
for c.hand.Len() < 4+n {
|
||||
if err := c.readRecord(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
data = c.hand.Next(4 + n)
|
||||
if err := c.readHandshakeBytes(4); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data := c.hand.Bytes()
|
||||
n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
|
||||
if n > maxHandshake {
|
||||
c.sendAlertLocked(alertInternalError)
|
||||
return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake))
|
||||
}
|
||||
if err := c.readHandshakeBytes(4 + n); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data = c.hand.Next(4 + n)
|
||||
return c.unmarshalHandshakeMessage(data, transcript)
|
||||
}
|
||||
|
||||
func (c *Conn) unmarshalHandshakeMessage(data []byte, transcript transcriptHash) (handshakeMessage, error) {
|
||||
var m handshakeMessage
|
||||
switch data[0] {
|
||||
case typeHelloRequest:
|
||||
@@ -1288,10 +1271,6 @@ func (c *Conn) handleRenegotiation() error {
|
||||
return c.handshakeErr
|
||||
}
|
||||
|
||||
func (c *Conn) HandlePostHandshakeMessage() error {
|
||||
return c.handlePostHandshakeMessage()
|
||||
}
|
||||
|
||||
// handlePostHandshakeMessage processes a handshake message arrived after the
|
||||
// handshake is complete. Up to TLS 1.2, it indicates the start of a renegotiation.
|
||||
func (c *Conn) handlePostHandshakeMessage() error {
|
||||
@@ -1303,7 +1282,6 @@ func (c *Conn) handlePostHandshakeMessage() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.retryCount++
|
||||
if c.retryCount > maxUselessRecords {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
@@ -1315,20 +1293,28 @@ func (c *Conn) handlePostHandshakeMessage() error {
|
||||
return c.handleNewSessionTicket(msg)
|
||||
case *keyUpdateMsg:
|
||||
return c.handleKeyUpdate(msg)
|
||||
default:
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return fmt.Errorf("tls: received unexpected handshake message of type %T", msg)
|
||||
}
|
||||
// The QUIC layer is supposed to treat an unexpected post-handshake CertificateRequest
|
||||
// as a QUIC-level PROTOCOL_VIOLATION error (RFC 9001, Section 4.4). Returning an
|
||||
// unexpected_message alert here doesn't provide it with enough information to distinguish
|
||||
// this condition from other unexpected messages. This is probably fine.
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return fmt.Errorf("tls: received unexpected handshake message of type %T", msg)
|
||||
}
|
||||
|
||||
func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
|
||||
if c.quic != nil {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return c.in.setErrorLocked(errors.New("tls: received unexpected key update message"))
|
||||
}
|
||||
|
||||
cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
|
||||
if cipherSuite == nil {
|
||||
return c.in.setErrorLocked(c.sendAlert(alertInternalError))
|
||||
}
|
||||
|
||||
newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret)
|
||||
c.in.setTrafficSecret(cipherSuite, newSecret)
|
||||
c.in.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
|
||||
|
||||
if keyUpdate.updateRequested {
|
||||
c.out.Lock()
|
||||
@@ -1347,7 +1333,7 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
|
||||
}
|
||||
|
||||
newSecret := cipherSuite.nextTrafficSecret(c.out.trafficSecret)
|
||||
c.out.setTrafficSecret(cipherSuite, newSecret)
|
||||
c.out.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -1508,12 +1494,15 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
||||
// 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 {
|
||||
if c.quic != nil {
|
||||
c.quic.cancelc = handshakeCtx.Done()
|
||||
c.quic.cancel = cancel
|
||||
} else if ctx.Done() != nil {
|
||||
// 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.
|
||||
done := make(chan struct{})
|
||||
interruptRes := make(chan error, 1)
|
||||
defer func() {
|
||||
@@ -1564,21 +1553,38 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
|
||||
panic("tls: internal error: handshake returned an error but is marked successful")
|
||||
}
|
||||
|
||||
if c.quic != nil {
|
||||
if c.handshakeErr == nil {
|
||||
c.quicHandshakeComplete()
|
||||
// Provide the 1-RTT read secret now that the handshake is complete.
|
||||
// The QUIC layer MUST NOT decrypt 1-RTT packets prior to completing
|
||||
// the handshake (RFC 9001, Section 5.7).
|
||||
c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret)
|
||||
} else {
|
||||
var a alert
|
||||
c.out.Lock()
|
||||
if !errors.As(c.out.err, &a) {
|
||||
a = alertInternalError
|
||||
}
|
||||
c.out.Unlock()
|
||||
// Return an error which wraps both the handshake error and
|
||||
// any alert error we may have sent, or alertInternalError
|
||||
// if we didn't send an alert.
|
||||
// Truncate the text of the alert to 0 characters.
|
||||
c.handshakeErr = fmt.Errorf("%w%.0w", c.handshakeErr, AlertError(a))
|
||||
}
|
||||
close(c.quic.blockedc)
|
||||
close(c.quic.signalc)
|
||||
}
|
||||
|
||||
return c.handshakeErr
|
||||
}
|
||||
|
||||
// ConnectionState returns basic TLS details about the connection.
|
||||
func (c *Conn) ConnectionState() ConnectionState {
|
||||
c.connStateMutex.Lock()
|
||||
defer c.connStateMutex.Unlock()
|
||||
return c.connState.ConnectionState
|
||||
}
|
||||
|
||||
// ConnectionStateWith0RTT returns basic TLS details (incl. 0-RTT status) about the connection.
|
||||
func (c *Conn) ConnectionStateWith0RTT() ConnectionStateWith0RTT {
|
||||
c.connStateMutex.Lock()
|
||||
defer c.connStateMutex.Unlock()
|
||||
return c.connState
|
||||
c.handshakeMutex.Lock()
|
||||
defer c.handshakeMutex.Unlock()
|
||||
return c.connectionStateLocked()
|
||||
}
|
||||
|
||||
func (c *Conn) connectionStateLocked() ConnectionState {
|
||||
@@ -1609,15 +1615,6 @@ func (c *Conn) connectionStateLocked() ConnectionState {
|
||||
return toConnectionState(state)
|
||||
}
|
||||
|
||||
func (c *Conn) updateConnectionState() {
|
||||
c.connStateMutex.Lock()
|
||||
defer c.connStateMutex.Unlock()
|
||||
c.connState = ConnectionStateWith0RTT{
|
||||
Used0RTT: c.used0RTT,
|
||||
ConnectionState: c.connectionStateLocked(),
|
||||
}
|
||||
}
|
||||
|
||||
// OCSPResponse returns the stapled OCSP response from the TLS server, if
|
||||
// any. (Only valid for client connections.)
|
||||
func (c *Conn) OCSPResponse() []byte {
|
||||
|
||||
22
vendor/github.com/quic-go/qtls-go1-20/cpu.go
generated
vendored
22
vendor/github.com/quic-go/qtls-go1-20/cpu.go
generated
vendored
@@ -1,22 +0,0 @@
|
||||
//go:build !js
|
||||
// +build !js
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
12
vendor/github.com/quic-go/qtls-go1-20/cpu_other.go
generated
vendored
12
vendor/github.com/quic-go/qtls-go1-20/cpu_other.go
generated
vendored
@@ -1,12 +0,0 @@
|
||||
//go:build js
|
||||
// +build js
|
||||
|
||||
package qtls
|
||||
|
||||
var (
|
||||
hasGCMAsmAMD64 = false
|
||||
hasGCMAsmARM64 = false
|
||||
hasGCMAsmS390X = false
|
||||
|
||||
hasAESGCMHardwareSupport = false
|
||||
)
|
||||
142
vendor/github.com/quic-go/qtls-go1-20/handshake_client.go
generated
vendored
142
vendor/github.com/quic-go/qtls-go1-20/handshake_client.go
generated
vendored
@@ -57,23 +57,12 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, clientKeySharePrivate, error)
|
||||
return nil, nil, errors.New("tls: NextProtos values too large")
|
||||
}
|
||||
|
||||
var supportedVersions []uint16
|
||||
var clientHelloVersion uint16
|
||||
if c.extraConfig.usesAlternativeRecordLayer() {
|
||||
if config.maxSupportedVersion(roleClient) < VersionTLS13 {
|
||||
return nil, nil, errors.New("tls: MaxVersion prevents QUIC from using TLS 1.3")
|
||||
}
|
||||
// Only offer TLS 1.3 when QUIC is used.
|
||||
supportedVersions = []uint16{VersionTLS13}
|
||||
clientHelloVersion = VersionTLS13
|
||||
} else {
|
||||
supportedVersions = config.supportedVersions(roleClient)
|
||||
if len(supportedVersions) == 0 {
|
||||
return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
|
||||
}
|
||||
clientHelloVersion = config.maxSupportedVersion(roleClient)
|
||||
supportedVersions := config.supportedVersions(roleClient)
|
||||
if len(supportedVersions) == 0 {
|
||||
return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
|
||||
}
|
||||
|
||||
clientHelloVersion := config.maxSupportedVersion(roleClient)
|
||||
// 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.
|
||||
@@ -127,7 +116,9 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, clientKeySharePrivate, error)
|
||||
// A random session ID is used to detect when the server accepted a ticket
|
||||
// and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as
|
||||
// a compatibility measure (see RFC 8446, Section 4.1.2).
|
||||
if c.extraConfig == nil || c.extraConfig.AlternativeRecordLayer == nil {
|
||||
//
|
||||
// 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 {
|
||||
return nil, nil, errors.New("tls: short read from Rand: " + err.Error())
|
||||
@@ -143,6 +134,9 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, clientKeySharePrivate, error)
|
||||
|
||||
var secret clientKeySharePrivate
|
||||
if hello.supportedVersions[0] == VersionTLS13 {
|
||||
if len(hello.supportedVersions) == 1 {
|
||||
hello.cipherSuites = hello.cipherSuites[:0]
|
||||
}
|
||||
if hasAESGCMHardwareSupport {
|
||||
hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
|
||||
} else {
|
||||
@@ -176,8 +170,15 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, clientKeySharePrivate, error)
|
||||
}
|
||||
}
|
||||
|
||||
if hello.supportedVersions[0] == VersionTLS13 && c.extraConfig != nil && c.extraConfig.GetExtensions != nil {
|
||||
hello.additionalExtensions = c.extraConfig.GetExtensions(typeClientHello)
|
||||
if c.quic != nil {
|
||||
p, err := c.quicGetTransportParameters()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if p == nil {
|
||||
p = []byte{}
|
||||
}
|
||||
hello.quicTransportParameters = p
|
||||
}
|
||||
|
||||
return hello, secret, nil
|
||||
@@ -187,7 +188,6 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
if c.config == nil {
|
||||
c.config = fromConfig(defaultConfig())
|
||||
}
|
||||
c.setAlternativeRecordLayer()
|
||||
|
||||
// This may be a renegotiation handshake, in which case some fields
|
||||
// need to be reset.
|
||||
@@ -204,45 +204,33 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
return err
|
||||
}
|
||||
if cacheKey != "" && session != nil {
|
||||
var deletedTicket bool
|
||||
if session.vers == VersionTLS13 && hello.earlyData && c.extraConfig != nil && c.extraConfig.Enable0RTT {
|
||||
// don't reuse a session ticket that enabled 0-RTT
|
||||
c.config.ClientSessionCache.Put(cacheKey, nil)
|
||||
deletedTicket = true
|
||||
|
||||
if suite := cipherSuiteTLS13ByID(session.cipherSuite); suite != nil {
|
||||
h := suite.hash.New()
|
||||
helloBytes, err := hello.marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.Write(helloBytes)
|
||||
clientEarlySecret := suite.deriveSecret(earlySecret, "c e traffic", h)
|
||||
c.out.exportKey(Encryption0RTT, suite, clientEarlySecret)
|
||||
if err := c.config.writeKeyLog(keyLogLabelEarlyTraffic, hello.random, clientEarlySecret); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
// If we got a handshake failure when resuming a session, throw away
|
||||
// the session ticket. See RFC 5077, Section 3.2.
|
||||
//
|
||||
// RFC 8446 makes no mention of dropping tickets on failure, but it
|
||||
// does require servers to abort on invalid binders, so we need to
|
||||
// delete tickets to recover from a corrupted PSK.
|
||||
if err != nil {
|
||||
c.config.ClientSessionCache.Put(cacheKey, nil)
|
||||
}
|
||||
}
|
||||
if !deletedTicket {
|
||||
defer func() {
|
||||
// If we got a handshake failure when resuming a session, throw away
|
||||
// the session ticket. See RFC 5077, Section 3.2.
|
||||
//
|
||||
// RFC 8446 makes no mention of dropping tickets on failure, but it
|
||||
// does require servers to abort on invalid binders, so we need to
|
||||
// delete tickets to recover from a corrupted PSK.
|
||||
if err != nil {
|
||||
c.config.ClientSessionCache.Put(cacheKey, nil)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hello.earlyData {
|
||||
suite := cipherSuiteTLS13ByID(session.cipherSuite)
|
||||
transcript := suite.hash.New()
|
||||
if err := transcriptMsg(hello, transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
earlyTrafficSecret := suite.deriveSecret(earlySecret, clientEarlyTrafficLabel, transcript)
|
||||
c.quicSetWriteSecret(QUICEncryptionLevelEarly, suite.id, earlyTrafficSecret)
|
||||
}
|
||||
|
||||
// serverHelloMsg is not included in the transcript
|
||||
msg, err := c.readHandshake(nil)
|
||||
if err != nil {
|
||||
@@ -305,7 +293,6 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) {
|
||||
c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(hs.session))
|
||||
}
|
||||
|
||||
c.updateConnectionState()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -358,7 +345,10 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
}
|
||||
|
||||
// Try to resume a previously negotiated TLS session, if available.
|
||||
cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
|
||||
cacheKey = c.clientSessionCacheKey()
|
||||
if cacheKey == "" {
|
||||
return "", nil, nil, nil, nil
|
||||
}
|
||||
sess, ok := c.config.ClientSessionCache.Get(cacheKey)
|
||||
if !ok || sess == nil {
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
@@ -442,6 +432,17 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
return cacheKey, nil, nil, nil, nil
|
||||
}
|
||||
|
||||
if c.quic != nil && maxEarlyData > 0 {
|
||||
var earlyData bool
|
||||
if session.vers == VersionTLS13 && c.extraConfig != nil && c.extraConfig.SetAppDataFromSessionState != nil {
|
||||
earlyData = c.extraConfig.SetAppDataFromSessionState(appData)
|
||||
}
|
||||
// For 0-RTT, the cipher suite has to match exactly.
|
||||
if earlyData && mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil {
|
||||
hello.earlyData = true
|
||||
}
|
||||
}
|
||||
|
||||
// Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
|
||||
ticketAge := uint32(c.config.time().Sub(session.receivedAt) / time.Millisecond)
|
||||
identity := pskIdentity{
|
||||
@@ -456,9 +457,6 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
session.nonce, cipherSuite.hash.Size())
|
||||
earlySecret = cipherSuite.extract(psk, nil)
|
||||
binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
|
||||
if c.extraConfig != nil {
|
||||
hello.earlyData = c.extraConfig.Enable0RTT && maxEarlyData > 0
|
||||
}
|
||||
transcript := cipherSuite.hash.New()
|
||||
helloBytes, err := hello.marshalWithoutBinders()
|
||||
if err != nil {
|
||||
@@ -470,9 +468,6 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
|
||||
return "", nil, nil, nil, err
|
||||
}
|
||||
|
||||
if session.vers == VersionTLS13 && c.extraConfig != nil && c.extraConfig.SetAppDataFromSessionState != nil {
|
||||
c.extraConfig.SetAppDataFromSessionState(appData)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -827,7 +822,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol); err != nil {
|
||||
if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol, false); err != nil {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
return false, err
|
||||
}
|
||||
@@ -865,8 +860,12 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
|
||||
|
||||
// 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 {
|
||||
func checkALPN(clientProtos []string, serverProto string, quic bool) error {
|
||||
if serverProto == "" {
|
||||
if quic && len(clientProtos) > 0 {
|
||||
// RFC 9001, Section 8.1
|
||||
return errors.New("tls: server did not select an ALPN protocol")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if len(clientProtos) == 0 {
|
||||
@@ -962,6 +961,10 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// maxRSAKeySize is the maximum RSA key size in bits that we are willing
|
||||
// to verify the signatures of during a TLS handshake.
|
||||
const maxRSAKeySize = 8192
|
||||
|
||||
// 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 {
|
||||
@@ -973,6 +976,10 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return errors.New("tls: failed to parse certificate from server: " + err.Error())
|
||||
}
|
||||
if cert.cert.PublicKeyAlgorithm == x509.RSA && cert.cert.PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", maxRSAKeySize)
|
||||
}
|
||||
activeHandles[i] = cert
|
||||
certs[i] = cert.cert
|
||||
}
|
||||
@@ -1106,15 +1113,16 @@ func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate,
|
||||
return new(Certificate), nil
|
||||
}
|
||||
|
||||
const clientSessionCacheKeyPrefix = "qtls-"
|
||||
|
||||
// clientSessionCacheKey returns a key used to cache sessionTickets that could
|
||||
// be used to resume previously negotiated TLS sessions with a server.
|
||||
func clientSessionCacheKey(serverAddr net.Addr, config *config) string {
|
||||
if len(config.ServerName) > 0 {
|
||||
return clientSessionCacheKeyPrefix + config.ServerName
|
||||
func (c *Conn) clientSessionCacheKey() string {
|
||||
if len(c.config.ServerName) > 0 {
|
||||
return c.config.ServerName
|
||||
}
|
||||
return clientSessionCacheKeyPrefix + serverAddr.String()
|
||||
if c.conn != nil {
|
||||
return c.conn.RemoteAddr().String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// hostnameInSNI converts name into an appropriate hostname for SNI.
|
||||
|
||||
86
vendor/github.com/quic-go/qtls-go1-20/handshake_client_tls13.go
generated
vendored
86
vendor/github.com/quic-go/qtls-go1-20/handshake_client_tls13.go
generated
vendored
@@ -91,7 +91,6 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||
if err := hs.processServerHello(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.updateConnectionState()
|
||||
if err := hs.sendDummyChangeCipherSpec(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -104,7 +103,6 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||
if err := hs.readServerCertificate(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.updateConnectionState()
|
||||
if err := hs.readServerFinished(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -125,7 +123,7 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
||||
})
|
||||
|
||||
c.isHandshakeComplete.Store(true)
|
||||
c.updateConnectionState()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -187,6 +185,9 @@ func (hs *clientHandshakeStateTLS13) checkServerHelloOrHRR() error {
|
||||
// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
|
||||
// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
|
||||
func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
|
||||
if hs.c.quic != nil {
|
||||
return nil
|
||||
}
|
||||
if hs.sentDummyCCS {
|
||||
return nil
|
||||
}
|
||||
@@ -293,7 +294,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||
transcript := hs.suite.hash.New()
|
||||
transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
|
||||
transcript.Write(chHash)
|
||||
if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
|
||||
if err := transcriptMsg(hs.serverHello, transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
helloBytes, err := hs.hello.marshalWithoutBinders()
|
||||
@@ -312,10 +313,11 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
|
||||
}
|
||||
}
|
||||
|
||||
if hs.hello.earlyData && c.extraConfig != nil && c.extraConfig.Rejected0RTT != nil {
|
||||
c.extraConfig.Rejected0RTT()
|
||||
if hs.hello.earlyData {
|
||||
hs.hello.earlyData = false
|
||||
c.quicRejectedEarlyData()
|
||||
}
|
||||
hs.hello.earlyData = false // disable 0-RTT
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -430,12 +432,18 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
|
||||
|
||||
clientSecret := hs.suite.deriveSecret(handshakeSecret,
|
||||
clientHandshakeTrafficLabel, hs.transcript)
|
||||
c.out.exportKey(EncryptionHandshake, hs.suite, clientSecret)
|
||||
c.out.setTrafficSecret(hs.suite, clientSecret)
|
||||
c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
|
||||
serverSecret := hs.suite.deriveSecret(handshakeSecret,
|
||||
serverHandshakeTrafficLabel, hs.transcript)
|
||||
c.in.exportKey(EncryptionHandshake, hs.suite, serverSecret)
|
||||
c.in.setTrafficSecret(hs.suite, serverSecret)
|
||||
c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
|
||||
|
||||
if c.quic != nil {
|
||||
if c.hand.Len() != 0 {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
}
|
||||
c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret)
|
||||
c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret)
|
||||
}
|
||||
|
||||
err = c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
|
||||
if err != nil {
|
||||
@@ -467,28 +475,35 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
return unexpectedMessageError(encryptedExtensions, msg)
|
||||
}
|
||||
// Notify the caller if 0-RTT was rejected.
|
||||
if !encryptedExtensions.earlyData && hs.hello.earlyData && c.extraConfig != nil && c.extraConfig.Rejected0RTT != nil {
|
||||
c.extraConfig.Rejected0RTT()
|
||||
}
|
||||
c.used0RTT = encryptedExtensions.earlyData
|
||||
if hs.c.extraConfig != nil && hs.c.extraConfig.ReceivedExtensions != nil {
|
||||
hs.c.extraConfig.ReceivedExtensions(typeEncryptedExtensions, encryptedExtensions.additionalExtensions)
|
||||
}
|
||||
|
||||
if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol, c.quic != nil); err != nil {
|
||||
// RFC 8446 specifies that no_application_protocol is sent by servers, but
|
||||
// does not specify how clients handle the selection of an incompatible protocol.
|
||||
// RFC 9001 Section 8.1 specifies that QUIC clients send no_application_protocol
|
||||
// in this case. Always sending no_application_protocol seems reasonable.
|
||||
c.sendAlert(alertNoApplicationProtocol)
|
||||
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 c.quic != nil {
|
||||
if encryptedExtensions.quicTransportParameters == nil {
|
||||
// RFC 9001 Section 8.2.
|
||||
c.sendAlert(alertMissingExtension)
|
||||
return errors.New("tls: server did not send a quic_transport_parameters extension")
|
||||
}
|
||||
c.quicSetTransportParameters(encryptedExtensions.quicTransportParameters)
|
||||
} else {
|
||||
if encryptedExtensions.quicTransportParameters != nil {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
return errors.New("tls: server sent an unexpected quic_transport_parameters extension")
|
||||
}
|
||||
}
|
||||
|
||||
if hs.hello.earlyData && !encryptedExtensions.earlyData {
|
||||
c.quicRejectedEarlyData()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -616,8 +631,7 @@ func (hs *clientHandshakeStateTLS13) readServerFinished() error {
|
||||
clientApplicationTrafficLabel, hs.transcript)
|
||||
serverSecret := hs.suite.deriveSecret(hs.masterSecret,
|
||||
serverApplicationTrafficLabel, hs.transcript)
|
||||
c.in.exportKey(EncryptionApplication, hs.suite, serverSecret)
|
||||
c.in.setTrafficSecret(hs.suite, serverSecret)
|
||||
c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
|
||||
|
||||
err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret)
|
||||
if err != nil {
|
||||
@@ -713,14 +727,20 @@ func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
|
||||
return err
|
||||
}
|
||||
|
||||
c.out.exportKey(EncryptionApplication, hs.suite, hs.trafficSecret)
|
||||
c.out.setTrafficSecret(hs.suite, hs.trafficSecret)
|
||||
c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
|
||||
|
||||
if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil {
|
||||
c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
|
||||
resumptionLabel, hs.transcript)
|
||||
}
|
||||
|
||||
if c.quic != nil {
|
||||
if c.hand.Len() != 0 {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
}
|
||||
c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, hs.trafficSecret)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -791,8 +811,10 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
|
||||
scts: c.scts,
|
||||
}
|
||||
|
||||
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
|
||||
c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(session))
|
||||
cacheKey := c.clientSessionCacheKey()
|
||||
if cacheKey != "" {
|
||||
c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(session))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
51
vendor/github.com/quic-go/qtls-go1-20/handshake_messages.go
generated
vendored
51
vendor/github.com/quic-go/qtls-go1-20/handshake_messages.go
generated
vendored
@@ -93,7 +93,7 @@ type clientHelloMsg struct {
|
||||
pskModes []uint8
|
||||
pskIdentities []pskIdentity
|
||||
pskBinders [][]byte
|
||||
additionalExtensions []Extension
|
||||
quicTransportParameters []byte
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) marshal() ([]byte, error) {
|
||||
@@ -247,10 +247,11 @@ func (m *clientHelloMsg) marshal() ([]byte, error) {
|
||||
})
|
||||
})
|
||||
}
|
||||
for _, ext := range m.additionalExtensions {
|
||||
exts.AddUint16(ext.Type)
|
||||
if m.quicTransportParameters != nil { // marshal zero-length parameters when present
|
||||
// RFC 9001, Section 8.2
|
||||
exts.AddUint16(extensionQUICTransportParameters)
|
||||
exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
|
||||
exts.AddBytes(ext.Data)
|
||||
exts.AddBytes(m.quicTransportParameters)
|
||||
})
|
||||
}
|
||||
if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
|
||||
@@ -567,6 +568,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
if !readUint8LengthPrefixed(&extData, &m.pskModes) {
|
||||
return false
|
||||
}
|
||||
case extensionQUICTransportParameters:
|
||||
m.quicTransportParameters = make([]byte, len(extData))
|
||||
if !extData.CopyBytes(m.quicTransportParameters) {
|
||||
return false
|
||||
}
|
||||
case extensionPreSharedKey:
|
||||
// RFC 8446, Section 4.2.11
|
||||
if !extensions.Empty() {
|
||||
@@ -598,7 +604,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
m.pskBinders = append(m.pskBinders, binder)
|
||||
}
|
||||
default:
|
||||
m.additionalExtensions = append(m.additionalExtensions, Extension{Type: extension, Data: extData})
|
||||
// Ignore unknown extensions.
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -867,11 +873,10 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
|
||||
}
|
||||
|
||||
type encryptedExtensionsMsg struct {
|
||||
raw []byte
|
||||
alpnProtocol string
|
||||
earlyData bool
|
||||
|
||||
additionalExtensions []Extension
|
||||
raw []byte
|
||||
alpnProtocol string
|
||||
quicTransportParameters []byte
|
||||
earlyData bool
|
||||
}
|
||||
|
||||
func (m *encryptedExtensionsMsg) marshal() ([]byte, error) {
|
||||
@@ -893,17 +898,18 @@ func (m *encryptedExtensionsMsg) marshal() ([]byte, error) {
|
||||
})
|
||||
})
|
||||
}
|
||||
if m.quicTransportParameters != nil { // marshal zero-length parameters when present
|
||||
// draft-ietf-quic-tls-32, Section 8.2
|
||||
b.AddUint16(extensionQUICTransportParameters)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(m.quicTransportParameters)
|
||||
})
|
||||
}
|
||||
if m.earlyData {
|
||||
// RFC 8446, Section 4.2.10
|
||||
b.AddUint16(extensionEarlyData)
|
||||
b.AddUint16(0) // empty extension_data
|
||||
}
|
||||
for _, ext := range m.additionalExtensions {
|
||||
b.AddUint16(ext.Type)
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(ext.Data)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -923,14 +929,14 @@ func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
|
||||
}
|
||||
|
||||
for !extensions.Empty() {
|
||||
var ext uint16
|
||||
var extension uint16
|
||||
var extData cryptobyte.String
|
||||
if !extensions.ReadUint16(&ext) ||
|
||||
if !extensions.ReadUint16(&extension) ||
|
||||
!extensions.ReadUint16LengthPrefixed(&extData) {
|
||||
return false
|
||||
}
|
||||
|
||||
switch ext {
|
||||
switch extension {
|
||||
case extensionALPN:
|
||||
var protoList cryptobyte.String
|
||||
if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
|
||||
@@ -942,10 +948,15 @@ func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
|
||||
return false
|
||||
}
|
||||
m.alpnProtocol = string(proto)
|
||||
case extensionQUICTransportParameters:
|
||||
m.quicTransportParameters = make([]byte, len(extData))
|
||||
if !extData.CopyBytes(m.quicTransportParameters) {
|
||||
return false
|
||||
}
|
||||
case extensionEarlyData:
|
||||
m.earlyData = true
|
||||
default:
|
||||
m.additionalExtensions = append(m.additionalExtensions, Extension{Type: ext, Data: extData})
|
||||
// Ignore unknown extensions.
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
42
vendor/github.com/quic-go/qtls-go1-20/handshake_server.go
generated
vendored
42
vendor/github.com/quic-go/qtls-go1-20/handshake_server.go
generated
vendored
@@ -39,8 +39,6 @@ type serverHandshakeState struct {
|
||||
|
||||
// serverHandshake performs a TLS handshake as a server.
|
||||
func (c *Conn) serverHandshake(ctx context.Context) error {
|
||||
c.setAlternativeRecordLayer()
|
||||
|
||||
clientHello, err := c.readClientHello(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -53,12 +51,6 @@ func (c *Conn) serverHandshake(ctx context.Context) error {
|
||||
clientHello: clientHello,
|
||||
}
|
||||
return hs.handshake()
|
||||
} else if c.extraConfig.usesAlternativeRecordLayer() {
|
||||
// This should already have been caught by the check that the ClientHello doesn't
|
||||
// offer any (supported) versions older than TLS 1.3.
|
||||
// Check again to make sure we can't be tricked into using an older version.
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return errors.New("tls: negotiated TLS < 1.3 when using QUIC")
|
||||
}
|
||||
|
||||
hs := serverHandshakeState{
|
||||
@@ -131,7 +123,6 @@ func (hs *serverHandshakeState) handshake() error {
|
||||
c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random)
|
||||
c.isHandshakeComplete.Store(true)
|
||||
|
||||
c.updateConnectionState()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -167,27 +158,6 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
|
||||
if len(clientHello.supportedVersions) == 0 {
|
||||
clientVersions = supportedVersionsFromMax(clientHello.vers)
|
||||
}
|
||||
if c.extraConfig.usesAlternativeRecordLayer() {
|
||||
// In QUIC, the client MUST NOT offer any old TLS versions.
|
||||
// Here, we can only check that none of the other supported versions of this library
|
||||
// (TLS 1.0 - TLS 1.2) is offered. We don't check for any SSL versions here.
|
||||
for _, ver := range clientVersions {
|
||||
if ver == VersionTLS13 {
|
||||
continue
|
||||
}
|
||||
for _, v := range supportedVersions {
|
||||
if ver == v {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
return nil, fmt.Errorf("tls: client offered old TLS version %#x", ver)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make the config we're using allows us to use TLS 1.3.
|
||||
if c.config.maxSupportedVersion(roleServer) < VersionTLS13 {
|
||||
c.sendAlert(alertInternalError)
|
||||
return nil, errors.New("tls: MaxVersion prevents QUIC from using TLS 1.3")
|
||||
}
|
||||
}
|
||||
c.vers, ok = c.config.mutualVersion(roleServer, clientVersions)
|
||||
if !ok {
|
||||
c.sendAlert(alertProtocolVersion)
|
||||
@@ -249,7 +219,7 @@ func (hs *serverHandshakeState) processClientHello() error {
|
||||
c.serverName = hs.clientHello.serverName
|
||||
}
|
||||
|
||||
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
|
||||
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, false)
|
||||
if err != nil {
|
||||
c.sendAlert(alertNoApplicationProtocol)
|
||||
return err
|
||||
@@ -310,8 +280,12 @@ func (hs *serverHandshakeState) processClientHello() error {
|
||||
// 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) {
|
||||
func negotiateALPN(serverProtos, clientProtos []string, quic bool) (string, error) {
|
||||
if len(serverProtos) == 0 || len(clientProtos) == 0 {
|
||||
if quic && len(serverProtos) != 0 {
|
||||
// RFC 9001, Section 8.1
|
||||
return "", fmt.Errorf("tls: client did not request an application protocol")
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
var http11fallback bool
|
||||
@@ -849,6 +823,10 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return errors.New("tls: failed to parse client certificate: " + err.Error())
|
||||
}
|
||||
if certs[i].PublicKeyAlgorithm == x509.RSA && certs[i].PublicKey.(*rsa.PublicKey).N.BitLen() > maxRSAKeySize {
|
||||
c.sendAlert(alertBadCertificate)
|
||||
return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", maxRSAKeySize)
|
||||
}
|
||||
}
|
||||
|
||||
if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) {
|
||||
|
||||
170
vendor/github.com/quic-go/qtls-go1-20/handshake_server_tls13.go
generated
vendored
170
vendor/github.com/quic-go/qtls-go1-20/handshake_server_tls13.go
generated
vendored
@@ -41,6 +41,7 @@ type serverHandshakeStateTLS13 struct {
|
||||
trafficSecret []byte // client_application_traffic_secret_0
|
||||
transcript hash.Hash
|
||||
clientFinished []byte
|
||||
earlyData bool
|
||||
}
|
||||
|
||||
func (hs *serverHandshakeStateTLS13) handshake() error {
|
||||
@@ -59,7 +60,6 @@ func (hs *serverHandshakeStateTLS13) handshake() error {
|
||||
if err := hs.checkForResumption(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.updateConnectionState()
|
||||
if err := hs.pickCertificate(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -82,7 +82,6 @@ func (hs *serverHandshakeStateTLS13) handshake() error {
|
||||
if err := hs.readClientCertificate(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.updateConnectionState()
|
||||
if err := hs.readClientFinished(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -94,7 +93,7 @@ func (hs *serverHandshakeStateTLS13) handshake() error {
|
||||
})
|
||||
|
||||
c.isHandshakeComplete.Store(true)
|
||||
c.updateConnectionState()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -236,13 +235,23 @@ GroupSelection:
|
||||
return errors.New("tls: invalid client key share")
|
||||
}
|
||||
|
||||
c.serverName = hs.clientHello.serverName
|
||||
|
||||
if c.extraConfig != nil && c.extraConfig.ReceivedExtensions != nil {
|
||||
c.extraConfig.ReceivedExtensions(typeClientHello, hs.clientHello.additionalExtensions)
|
||||
if c.quic != nil {
|
||||
if hs.clientHello.quicTransportParameters == nil {
|
||||
// RFC 9001 Section 8.2.
|
||||
c.sendAlert(alertMissingExtension)
|
||||
return errors.New("tls: client did not send a quic_transport_parameters extension")
|
||||
}
|
||||
c.quicSetTransportParameters(hs.clientHello.quicTransportParameters)
|
||||
} else {
|
||||
if hs.clientHello.quicTransportParameters != nil {
|
||||
c.sendAlert(alertUnsupportedExtension)
|
||||
return errors.New("tls: client sent an unexpected quic_transport_parameters extension")
|
||||
}
|
||||
}
|
||||
|
||||
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
|
||||
c.serverName = hs.clientHello.serverName
|
||||
|
||||
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil)
|
||||
if err != nil {
|
||||
hs.alpnNegotiationErr = err
|
||||
}
|
||||
@@ -299,10 +308,9 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
|
||||
}
|
||||
|
||||
if hs.alpnNegotiationErr == nil && sessionState.alpn == c.clientProtocol &&
|
||||
c.extraConfig != nil && c.extraConfig.MaxEarlyData > 0 &&
|
||||
c.extraConfig != nil && c.extraConfig.Enable0RTT &&
|
||||
c.extraConfig.Accept0RTT != nil && c.extraConfig.Accept0RTT(sessionState.appData) {
|
||||
hs.encryptedExtensions.earlyData = true
|
||||
c.used0RTT = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,27 +362,23 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
|
||||
return errors.New("tls: invalid PSK binder")
|
||||
}
|
||||
|
||||
if c.quic != nil && hs.clientHello.earlyData && hs.encryptedExtensions.earlyData && i == 0 &&
|
||||
sessionState.maxEarlyData > 0 && sessionState.cipherSuite == hs.suite.id {
|
||||
hs.earlyData = true
|
||||
|
||||
transcript := hs.suite.hash.New()
|
||||
if err := transcriptMsg(hs.clientHello, transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
earlyTrafficSecret := hs.suite.deriveSecret(hs.earlySecret, clientEarlyTrafficLabel, transcript)
|
||||
c.quicSetReadSecret(QUICEncryptionLevelEarly, hs.suite.id, earlyTrafficSecret)
|
||||
}
|
||||
|
||||
c.didResume = true
|
||||
if err := c.processCertsFromClient(sessionState.certificate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h := cloneHash(hs.transcript, hs.suite.hash)
|
||||
clientHelloWithBindersBytes, err := hs.clientHello.marshal()
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
h.Write(clientHelloWithBindersBytes)
|
||||
if hs.encryptedExtensions.earlyData {
|
||||
clientEarlySecret := hs.suite.deriveSecret(hs.earlySecret, "c e traffic", h)
|
||||
c.in.exportKey(Encryption0RTT, hs.suite, clientEarlySecret)
|
||||
if err := c.config.writeKeyLog(keyLogLabelEarlyTraffic, hs.clientHello.random, clientEarlySecret); err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
hs.hello.selectedIdentityPresent = true
|
||||
hs.hello.selectedIdentity = uint16(i)
|
||||
hs.usingPSK = true
|
||||
@@ -449,6 +453,9 @@ func (hs *serverHandshakeStateTLS13) pickCertificate() error {
|
||||
// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
|
||||
// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
|
||||
func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
|
||||
if hs.c.quic != nil {
|
||||
return nil
|
||||
}
|
||||
if hs.sentDummyCCS {
|
||||
return nil
|
||||
}
|
||||
@@ -517,9 +524,9 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID)
|
||||
return errors.New("tls: client illegally modified second ClientHello")
|
||||
}
|
||||
|
||||
if clientHello.earlyData {
|
||||
if illegalClientHelloChange(clientHello, hs.clientHello) {
|
||||
c.sendAlert(alertIllegalParameter)
|
||||
return errors.New("tls: client offered 0-RTT data in second ClientHello")
|
||||
return errors.New("tls: client illegally modified second ClientHello")
|
||||
}
|
||||
|
||||
hs.clientHello = clientHello
|
||||
@@ -607,12 +614,18 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
|
||||
|
||||
clientSecret := hs.suite.deriveSecret(hs.handshakeSecret,
|
||||
clientHandshakeTrafficLabel, hs.transcript)
|
||||
c.in.exportKey(EncryptionHandshake, hs.suite, clientSecret)
|
||||
c.in.setTrafficSecret(hs.suite, clientSecret)
|
||||
c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
|
||||
serverSecret := hs.suite.deriveSecret(hs.handshakeSecret,
|
||||
serverHandshakeTrafficLabel, hs.transcript)
|
||||
c.out.exportKey(EncryptionHandshake, hs.suite, serverSecret)
|
||||
c.out.setTrafficSecret(hs.suite, serverSecret)
|
||||
c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
|
||||
|
||||
if c.quic != nil {
|
||||
if c.hand.Len() != 0 {
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
}
|
||||
c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret)
|
||||
c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret)
|
||||
}
|
||||
|
||||
err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret)
|
||||
if err != nil {
|
||||
@@ -625,12 +638,20 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if hs.alpnNegotiationErr != nil {
|
||||
selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil)
|
||||
if err != nil {
|
||||
c.sendAlert(alertNoApplicationProtocol)
|
||||
return hs.alpnNegotiationErr
|
||||
return err
|
||||
}
|
||||
if hs.c.extraConfig != nil && hs.c.extraConfig.GetExtensions != nil {
|
||||
hs.encryptedExtensions.additionalExtensions = hs.c.extraConfig.GetExtensions(typeEncryptedExtensions)
|
||||
hs.encryptedExtensions.alpnProtocol = selectedProto
|
||||
c.clientProtocol = selectedProto
|
||||
|
||||
if c.quic != nil {
|
||||
p, err := c.quicGetTransportParameters()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hs.encryptedExtensions.quicTransportParameters = p
|
||||
}
|
||||
|
||||
if _, err := hs.c.writeHandshakeRecord(hs.encryptedExtensions, hs.transcript); err != nil {
|
||||
@@ -731,8 +752,15 @@ func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
|
||||
clientApplicationTrafficLabel, hs.transcript)
|
||||
serverSecret := hs.suite.deriveSecret(hs.masterSecret,
|
||||
serverApplicationTrafficLabel, hs.transcript)
|
||||
c.out.exportKey(EncryptionApplication, hs.suite, serverSecret)
|
||||
c.out.setTrafficSecret(hs.suite, serverSecret)
|
||||
c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
|
||||
|
||||
if c.quic != nil {
|
||||
if c.hand.Len() != 0 {
|
||||
// TODO: Handle this in setTrafficSecret?
|
||||
c.sendAlert(alertUnexpectedMessage)
|
||||
}
|
||||
c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, serverSecret)
|
||||
}
|
||||
|
||||
err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret)
|
||||
if err != nil {
|
||||
@@ -764,6 +792,10 @@ func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// QUIC tickets are sent by QUICConn.SendSessionTicket, not automatically.
|
||||
if hs.c.quic != nil {
|
||||
return false
|
||||
}
|
||||
// Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9.
|
||||
for _, pskMode := range hs.clientHello.pskModes {
|
||||
if pskMode == pskModeDHE {
|
||||
@@ -783,25 +815,66 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
|
||||
if err := transcriptMsg(finishedMsg, hs.transcript); err != nil {
|
||||
return err
|
||||
}
|
||||
c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
|
||||
resumptionLabel, hs.transcript)
|
||||
|
||||
if !hs.shouldSendSessionTickets() {
|
||||
return nil
|
||||
}
|
||||
return c.sendSessionTicket(false)
|
||||
}
|
||||
|
||||
c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
|
||||
resumptionLabel, hs.transcript)
|
||||
|
||||
// Don't send session tickets when the alternative record layer is set.
|
||||
// Instead, save the resumption secret on the Conn.
|
||||
// Session tickets can then be generated by calling Conn.GetSessionTicket().
|
||||
if hs.c.extraConfig != nil && hs.c.extraConfig.AlternativeRecordLayer != nil {
|
||||
return nil
|
||||
func (c *Conn) sendSessionTicket(earlyData bool) error {
|
||||
suite := cipherSuiteTLS13ByID(c.cipherSuite)
|
||||
if suite == nil {
|
||||
return errors.New("tls: internal error: unknown cipher suite")
|
||||
}
|
||||
|
||||
m, err := hs.c.getSessionTicketMsg(nil)
|
||||
m := new(newSessionTicketMsgTLS13)
|
||||
|
||||
var certsFromClient [][]byte
|
||||
for _, cert := range c.peerCertificates {
|
||||
certsFromClient = append(certsFromClient, cert.Raw)
|
||||
}
|
||||
state := sessionStateTLS13{
|
||||
cipherSuite: suite.id,
|
||||
createdAt: uint64(c.config.time().Unix()),
|
||||
resumptionSecret: c.resumptionSecret,
|
||||
certificate: Certificate{
|
||||
Certificate: certsFromClient,
|
||||
OCSPStaple: c.ocspResponse,
|
||||
SignedCertificateTimestamps: c.scts,
|
||||
},
|
||||
alpn: c.clientProtocol,
|
||||
}
|
||||
if earlyData {
|
||||
state.maxEarlyData = 0xffffffff
|
||||
state.appData = c.extraConfig.GetAppDataForSessionTicket()
|
||||
}
|
||||
stateBytes, err := state.marshal()
|
||||
if err != nil {
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
m.label, err = c.encryptTicket(stateBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
|
||||
|
||||
// ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1
|
||||
// The value is not stored anywhere; we never need to check the ticket age
|
||||
// because 0-RTT is not supported.
|
||||
ageAdd := make([]byte, 4)
|
||||
_, err = c.config.rand().Read(ageAdd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if earlyData {
|
||||
// RFC 9001, Section 4.6.1
|
||||
m.maxEarlyData = 0xffffffff
|
||||
}
|
||||
|
||||
if _, err := c.writeHandshakeRecord(m, nil); err != nil {
|
||||
return err
|
||||
@@ -919,8 +992,7 @@ func (hs *serverHandshakeStateTLS13) readClientFinished() error {
|
||||
return errors.New("tls: invalid client finished hash")
|
||||
}
|
||||
|
||||
c.in.exportKey(EncryptionApplication, hs.suite, hs.trafficSecret)
|
||||
c.in.setTrafficSecret(hs.suite, hs.trafficSecret)
|
||||
c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
1
vendor/github.com/quic-go/qtls-go1-20/key_schedule.go
generated
vendored
1
vendor/github.com/quic-go/qtls-go1-20/key_schedule.go
generated
vendored
@@ -21,6 +21,7 @@ import (
|
||||
|
||||
const (
|
||||
resumptionBinderLabel = "res binder"
|
||||
clientEarlyTrafficLabel = "c e traffic"
|
||||
clientHandshakeTrafficLabel = "c hs traffic"
|
||||
serverHandshakeTrafficLabel = "s hs traffic"
|
||||
clientApplicationTrafficLabel = "c ap traffic"
|
||||
|
||||
418
vendor/github.com/quic-go/qtls-go1-20/quic.go
generated
vendored
Normal file
418
vendor/github.com/quic-go/qtls-go1-20/quic.go
generated
vendored
Normal file
@@ -0,0 +1,418 @@
|
||||
// Copyright 2023 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 qtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// QUICEncryptionLevel represents a QUIC encryption level used to transmit
|
||||
// handshake messages.
|
||||
type QUICEncryptionLevel int
|
||||
|
||||
const (
|
||||
QUICEncryptionLevelInitial = QUICEncryptionLevel(iota)
|
||||
QUICEncryptionLevelEarly
|
||||
QUICEncryptionLevelHandshake
|
||||
QUICEncryptionLevelApplication
|
||||
)
|
||||
|
||||
func (l QUICEncryptionLevel) String() string {
|
||||
switch l {
|
||||
case QUICEncryptionLevelInitial:
|
||||
return "Initial"
|
||||
case QUICEncryptionLevelEarly:
|
||||
return "Early"
|
||||
case QUICEncryptionLevelHandshake:
|
||||
return "Handshake"
|
||||
case QUICEncryptionLevelApplication:
|
||||
return "Application"
|
||||
default:
|
||||
return fmt.Sprintf("QUICEncryptionLevel(%v)", int(l))
|
||||
}
|
||||
}
|
||||
|
||||
// A QUICConn represents a connection which uses a QUIC implementation as the underlying
|
||||
// transport as described in RFC 9001.
|
||||
//
|
||||
// Methods of QUICConn are not safe for concurrent use.
|
||||
type QUICConn struct {
|
||||
conn *Conn
|
||||
|
||||
sessionTicketSent bool
|
||||
}
|
||||
|
||||
// A QUICConfig configures a QUICConn.
|
||||
type QUICConfig struct {
|
||||
TLSConfig *Config
|
||||
ExtraConfig *ExtraConfig
|
||||
}
|
||||
|
||||
// A QUICEventKind is a type of operation on a QUIC connection.
|
||||
type QUICEventKind int
|
||||
|
||||
const (
|
||||
// QUICNoEvent indicates that there are no events available.
|
||||
QUICNoEvent QUICEventKind = iota
|
||||
|
||||
// QUICSetReadSecret and QUICSetWriteSecret provide the read and write
|
||||
// secrets for a given encryption level.
|
||||
// QUICEvent.Level, QUICEvent.Data, and QUICEvent.Suite are set.
|
||||
//
|
||||
// Secrets for the Initial encryption level are derived from the initial
|
||||
// destination connection ID, and are not provided by the QUICConn.
|
||||
QUICSetReadSecret
|
||||
QUICSetWriteSecret
|
||||
|
||||
// QUICWriteData provides data to send to the peer in CRYPTO frames.
|
||||
// QUICEvent.Data is set.
|
||||
QUICWriteData
|
||||
|
||||
// QUICTransportParameters provides the peer's QUIC transport parameters.
|
||||
// QUICEvent.Data is set.
|
||||
QUICTransportParameters
|
||||
|
||||
// QUICTransportParametersRequired indicates that the caller must provide
|
||||
// QUIC transport parameters to send to the peer. The caller should set
|
||||
// the transport parameters with QUICConn.SetTransportParameters and call
|
||||
// QUICConn.NextEvent again.
|
||||
//
|
||||
// If transport parameters are set before calling QUICConn.Start, the
|
||||
// connection will never generate a QUICTransportParametersRequired event.
|
||||
QUICTransportParametersRequired
|
||||
|
||||
// QUICRejectedEarlyData indicates that the server rejected 0-RTT data even
|
||||
// if we offered it. It's returned before QUICEncryptionLevelApplication
|
||||
// keys are returned.
|
||||
QUICRejectedEarlyData
|
||||
|
||||
// QUICHandshakeDone indicates that the TLS handshake has completed.
|
||||
QUICHandshakeDone
|
||||
)
|
||||
|
||||
// A QUICEvent is an event occurring on a QUIC connection.
|
||||
//
|
||||
// The type of event is specified by the Kind field.
|
||||
// The contents of the other fields are kind-specific.
|
||||
type QUICEvent struct {
|
||||
Kind QUICEventKind
|
||||
|
||||
// Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
|
||||
Level QUICEncryptionLevel
|
||||
|
||||
// Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
|
||||
// The contents are owned by crypto/tls, and are valid until the next NextEvent call.
|
||||
Data []byte
|
||||
|
||||
// Set for QUICSetReadSecret and QUICSetWriteSecret.
|
||||
Suite uint16
|
||||
}
|
||||
|
||||
type quicState struct {
|
||||
events []QUICEvent
|
||||
nextEvent int
|
||||
|
||||
// eventArr is a statically allocated event array, large enough to handle
|
||||
// the usual maximum number of events resulting from a single call: transport
|
||||
// parameters, Initial data, Early read secret, Handshake write and read
|
||||
// secrets, Handshake data, Application write secret, Application data.
|
||||
eventArr [8]QUICEvent
|
||||
|
||||
started bool
|
||||
signalc chan struct{} // handshake data is available to be read
|
||||
blockedc chan struct{} // handshake is waiting for data, closed when done
|
||||
cancelc <-chan struct{} // handshake has been canceled
|
||||
cancel context.CancelFunc
|
||||
|
||||
// readbuf is shared between HandleData and the handshake goroutine.
|
||||
// HandshakeCryptoData passes ownership to the handshake goroutine by
|
||||
// reading from signalc, and reclaims ownership by reading from blockedc.
|
||||
readbuf []byte
|
||||
|
||||
transportParams []byte // to send to the peer
|
||||
}
|
||||
|
||||
// QUICClient returns a new TLS client side connection using QUICTransport as the
|
||||
// underlying transport. The config cannot be nil.
|
||||
//
|
||||
// The config's MinVersion must be at least TLS 1.3.
|
||||
func QUICClient(config *QUICConfig) *QUICConn {
|
||||
return newQUICConn(Client(nil, config.TLSConfig), config.ExtraConfig)
|
||||
}
|
||||
|
||||
// QUICServer returns a new TLS server side connection using QUICTransport as the
|
||||
// underlying transport. The config cannot be nil.
|
||||
//
|
||||
// The config's MinVersion must be at least TLS 1.3.
|
||||
func QUICServer(config *QUICConfig) *QUICConn {
|
||||
return newQUICConn(Server(nil, config.TLSConfig), config.ExtraConfig)
|
||||
}
|
||||
|
||||
func newQUICConn(conn *Conn, extraConfig *ExtraConfig) *QUICConn {
|
||||
conn.quic = &quicState{
|
||||
signalc: make(chan struct{}),
|
||||
blockedc: make(chan struct{}),
|
||||
}
|
||||
conn.quic.events = conn.quic.eventArr[:0]
|
||||
conn.extraConfig = extraConfig
|
||||
return &QUICConn{
|
||||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
// Start starts the client or server handshake protocol.
|
||||
// It may produce connection events, which may be read with NextEvent.
|
||||
//
|
||||
// Start must be called at most once.
|
||||
func (q *QUICConn) Start(ctx context.Context) error {
|
||||
if q.conn.quic.started {
|
||||
return quicError(errors.New("tls: Start called more than once"))
|
||||
}
|
||||
q.conn.quic.started = true
|
||||
if q.conn.config.MinVersion < VersionTLS13 {
|
||||
return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13"))
|
||||
}
|
||||
go q.conn.HandshakeContext(ctx)
|
||||
if _, ok := <-q.conn.quic.blockedc; !ok {
|
||||
return q.conn.handshakeErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NextEvent returns the next event occurring on the connection.
|
||||
// It returns an event with a Kind of QUICNoEvent when no events are available.
|
||||
func (q *QUICConn) NextEvent() QUICEvent {
|
||||
qs := q.conn.quic
|
||||
if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
|
||||
// Write over some of the previous event's data,
|
||||
// to catch callers erroniously retaining it.
|
||||
qs.events[last].Data[0] = 0
|
||||
}
|
||||
if qs.nextEvent >= len(qs.events) {
|
||||
qs.events = qs.events[:0]
|
||||
qs.nextEvent = 0
|
||||
return QUICEvent{Kind: QUICNoEvent}
|
||||
}
|
||||
e := qs.events[qs.nextEvent]
|
||||
qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data
|
||||
qs.nextEvent++
|
||||
return e
|
||||
}
|
||||
|
||||
// Close closes the connection and stops any in-progress handshake.
|
||||
func (q *QUICConn) Close() error {
|
||||
if q.conn.quic.cancel == nil {
|
||||
return nil // never started
|
||||
}
|
||||
q.conn.quic.cancel()
|
||||
for range q.conn.quic.blockedc {
|
||||
// Wait for the handshake goroutine to return.
|
||||
}
|
||||
return q.conn.handshakeErr
|
||||
}
|
||||
|
||||
// HandleData handles handshake bytes received from the peer.
|
||||
// It may produce connection events, which may be read with NextEvent.
|
||||
func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
|
||||
c := q.conn
|
||||
if c.in.level != level {
|
||||
return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
|
||||
}
|
||||
c.quic.readbuf = data
|
||||
<-c.quic.signalc
|
||||
_, ok := <-c.quic.blockedc
|
||||
if ok {
|
||||
// The handshake goroutine is waiting for more data.
|
||||
return nil
|
||||
}
|
||||
// The handshake goroutine has exited.
|
||||
c.handshakeMutex.Lock()
|
||||
defer c.handshakeMutex.Unlock()
|
||||
c.hand.Write(c.quic.readbuf)
|
||||
c.quic.readbuf = nil
|
||||
for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
|
||||
b := q.conn.hand.Bytes()
|
||||
n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
|
||||
if n > maxHandshake {
|
||||
q.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)
|
||||
break
|
||||
}
|
||||
if len(b) < 4+n {
|
||||
return nil
|
||||
}
|
||||
if err := q.conn.handlePostHandshakeMessage(); err != nil {
|
||||
q.conn.handshakeErr = err
|
||||
}
|
||||
}
|
||||
if q.conn.handshakeErr != nil {
|
||||
return quicError(q.conn.handshakeErr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendSessionTicket sends a session ticket to the client.
|
||||
// It produces connection events, which may be read with NextEvent.
|
||||
// Currently, it can only be called once.
|
||||
func (q *QUICConn) SendSessionTicket(earlyData bool) error {
|
||||
c := q.conn
|
||||
if !c.isHandshakeComplete.Load() {
|
||||
return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
|
||||
}
|
||||
if c.isClient {
|
||||
return quicError(errors.New("tls: SendSessionTicket called on the client"))
|
||||
}
|
||||
if q.sessionTicketSent {
|
||||
return quicError(errors.New("tls: SendSessionTicket called multiple times"))
|
||||
}
|
||||
q.sessionTicketSent = true
|
||||
return quicError(c.sendSessionTicket(earlyData))
|
||||
}
|
||||
|
||||
// ConnectionState returns basic TLS details about the connection.
|
||||
func (q *QUICConn) ConnectionState() ConnectionState {
|
||||
return q.conn.ConnectionState()
|
||||
}
|
||||
|
||||
// SetTransportParameters sets the transport parameters to send to the peer.
|
||||
//
|
||||
// Server connections may delay setting the transport parameters until after
|
||||
// receiving the client's transport parameters. See QUICTransportParametersRequired.
|
||||
func (q *QUICConn) SetTransportParameters(params []byte) {
|
||||
if params == nil {
|
||||
params = []byte{}
|
||||
}
|
||||
q.conn.quic.transportParams = params
|
||||
if q.conn.quic.started {
|
||||
<-q.conn.quic.signalc
|
||||
<-q.conn.quic.blockedc
|
||||
}
|
||||
}
|
||||
|
||||
// quicError ensures err is an AlertError.
|
||||
// If err is not already, quicError wraps it with alertInternalError.
|
||||
func quicError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
var ae AlertError
|
||||
if errors.As(err, &ae) {
|
||||
return err
|
||||
}
|
||||
var a alert
|
||||
if !errors.As(err, &a) {
|
||||
a = alertInternalError
|
||||
}
|
||||
// Return an error wrapping the original error and an AlertError.
|
||||
// Truncate the text of the alert to 0 characters.
|
||||
return fmt.Errorf("%w%.0w", err, AlertError(a))
|
||||
}
|
||||
|
||||
func (c *Conn) quicReadHandshakeBytes(n int) error {
|
||||
for c.hand.Len() < n {
|
||||
if err := c.quicWaitForSignal(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
|
||||
c.quic.events = append(c.quic.events, QUICEvent{
|
||||
Kind: QUICSetReadSecret,
|
||||
Level: level,
|
||||
Suite: suite,
|
||||
Data: secret,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
|
||||
c.quic.events = append(c.quic.events, QUICEvent{
|
||||
Kind: QUICSetWriteSecret,
|
||||
Level: level,
|
||||
Suite: suite,
|
||||
Data: secret,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) {
|
||||
var last *QUICEvent
|
||||
if len(c.quic.events) > 0 {
|
||||
last = &c.quic.events[len(c.quic.events)-1]
|
||||
}
|
||||
if last == nil || last.Kind != QUICWriteData || last.Level != level {
|
||||
c.quic.events = append(c.quic.events, QUICEvent{
|
||||
Kind: QUICWriteData,
|
||||
Level: level,
|
||||
})
|
||||
last = &c.quic.events[len(c.quic.events)-1]
|
||||
}
|
||||
last.Data = append(last.Data, data...)
|
||||
}
|
||||
|
||||
func (c *Conn) quicSetTransportParameters(params []byte) {
|
||||
c.quic.events = append(c.quic.events, QUICEvent{
|
||||
Kind: QUICTransportParameters,
|
||||
Data: params,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Conn) quicGetTransportParameters() ([]byte, error) {
|
||||
if c.quic.transportParams == nil {
|
||||
c.quic.events = append(c.quic.events, QUICEvent{
|
||||
Kind: QUICTransportParametersRequired,
|
||||
})
|
||||
}
|
||||
for c.quic.transportParams == nil {
|
||||
if err := c.quicWaitForSignal(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c.quic.transportParams, nil
|
||||
}
|
||||
|
||||
func (c *Conn) quicHandshakeComplete() {
|
||||
c.quic.events = append(c.quic.events, QUICEvent{
|
||||
Kind: QUICHandshakeDone,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Conn) quicRejectedEarlyData() {
|
||||
c.quic.events = append(c.quic.events, QUICEvent{
|
||||
Kind: QUICRejectedEarlyData,
|
||||
})
|
||||
}
|
||||
|
||||
// quicWaitForSignal notifies the QUICConn that handshake progress is blocked,
|
||||
// and waits for a signal that the handshake should proceed.
|
||||
//
|
||||
// The handshake may become blocked waiting for handshake bytes
|
||||
// or for the user to provide transport parameters.
|
||||
func (c *Conn) quicWaitForSignal() error {
|
||||
// Drop the handshake mutex while blocked to allow the user
|
||||
// to call ConnectionState before the handshake completes.
|
||||
c.handshakeMutex.Unlock()
|
||||
defer c.handshakeMutex.Lock()
|
||||
// Send on blockedc to notify the QUICConn that the handshake is blocked.
|
||||
// Exported methods of QUICConn wait for the handshake to become blocked
|
||||
// before returning to the user.
|
||||
select {
|
||||
case c.quic.blockedc <- struct{}{}:
|
||||
case <-c.quic.cancelc:
|
||||
return c.sendAlertLocked(alertCloseNotify)
|
||||
}
|
||||
// The QUICConn reads from signalc to notify us that the handshake may
|
||||
// be able to proceed. (The QUICConn reads, because we close signalc to
|
||||
// indicate that the handshake has completed.)
|
||||
select {
|
||||
case c.quic.signalc <- struct{}{}:
|
||||
c.hand.Write(c.quic.readbuf)
|
||||
c.quic.readbuf = nil
|
||||
case <-c.quic.cancelc:
|
||||
return c.sendAlertLocked(alertCloseNotify)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
76
vendor/github.com/quic-go/qtls-go1-20/ticket.go
generated
vendored
76
vendor/github.com/quic-go/qtls-go1-20/ticket.go
generated
vendored
@@ -11,12 +11,9 @@ import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
"io"
|
||||
)
|
||||
|
||||
// sessionState contains the information that is serialized into a session
|
||||
@@ -204,74 +201,3 @@ func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey boo
|
||||
|
||||
return plaintext, keyIndex > 0
|
||||
}
|
||||
|
||||
func (c *Conn) getSessionTicketMsg(appData []byte) (*newSessionTicketMsgTLS13, error) {
|
||||
m := new(newSessionTicketMsgTLS13)
|
||||
|
||||
var certsFromClient [][]byte
|
||||
for _, cert := range c.peerCertificates {
|
||||
certsFromClient = append(certsFromClient, cert.Raw)
|
||||
}
|
||||
state := sessionStateTLS13{
|
||||
cipherSuite: c.cipherSuite,
|
||||
createdAt: uint64(c.config.time().Unix()),
|
||||
resumptionSecret: c.resumptionSecret,
|
||||
certificate: Certificate{
|
||||
Certificate: certsFromClient,
|
||||
OCSPStaple: c.ocspResponse,
|
||||
SignedCertificateTimestamps: c.scts,
|
||||
},
|
||||
appData: appData,
|
||||
alpn: c.clientProtocol,
|
||||
}
|
||||
if c.extraConfig != nil {
|
||||
state.maxEarlyData = c.extraConfig.MaxEarlyData
|
||||
}
|
||||
stateBytes, err := state.marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.label, err = c.encryptTicket(stateBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
|
||||
|
||||
// ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1
|
||||
// The value is not stored anywhere; we never need to check the ticket age
|
||||
// because 0-RTT is not supported.
|
||||
ageAdd := make([]byte, 4)
|
||||
_, err = c.config.rand().Read(ageAdd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.ageAdd = binary.LittleEndian.Uint32(ageAdd)
|
||||
|
||||
// ticket_nonce, which must be unique per connection, is always left at
|
||||
// zero because we only ever send one ticket per connection.
|
||||
|
||||
if c.extraConfig != nil {
|
||||
m.maxEarlyData = c.extraConfig.MaxEarlyData
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// GetSessionTicket generates a new session ticket.
|
||||
// It should only be called after the handshake completes.
|
||||
// It can only be used for servers, and only if the alternative record layer is set.
|
||||
// The ticket may be nil if config.SessionTicketsDisabled is set,
|
||||
// or if the client isn't able to receive session tickets.
|
||||
func (c *Conn) GetSessionTicket(appData []byte) ([]byte, error) {
|
||||
if c.isClient || !c.isHandshakeComplete.Load() || c.extraConfig == nil || c.extraConfig.AlternativeRecordLayer == nil {
|
||||
return nil, errors.New("GetSessionTicket is only valid for servers after completion of the handshake, and if an alternative record layer is set.")
|
||||
}
|
||||
if c.config.SessionTicketsDisabled {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
m, err := c.getSessionTicketMsg(appData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m.marshal()
|
||||
}
|
||||
|
||||
44
vendor/github.com/quic-go/qtls-go1-20/tls.go
generated
vendored
44
vendor/github.com/quic-go/qtls-go1-20/tls.go
generated
vendored
@@ -31,11 +31,10 @@ import (
|
||||
// using conn as the underlying transport.
|
||||
// The configuration config must be non-nil and must include
|
||||
// at least one certificate or else set GetCertificate.
|
||||
func Server(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
func Server(conn net.Conn, config *Config) *Conn {
|
||||
c := &Conn{
|
||||
conn: conn,
|
||||
config: fromConfig(config),
|
||||
extraConfig: extraConfig,
|
||||
conn: conn,
|
||||
config: fromConfig(config),
|
||||
}
|
||||
c.handshakeFn = c.serverHandshake
|
||||
return c
|
||||
@@ -45,12 +44,11 @@ func Server(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
// using conn as the underlying transport.
|
||||
// The config cannot be nil: users must set either ServerName or
|
||||
// InsecureSkipVerify in the config.
|
||||
func Client(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
func Client(conn net.Conn, config *Config) *Conn {
|
||||
c := &Conn{
|
||||
conn: conn,
|
||||
config: fromConfig(config),
|
||||
extraConfig: extraConfig,
|
||||
isClient: true,
|
||||
conn: conn,
|
||||
config: fromConfig(config),
|
||||
isClient: true,
|
||||
}
|
||||
c.handshakeFn = c.clientHandshake
|
||||
return c
|
||||
@@ -59,8 +57,7 @@ func Client(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
// A listener implements a network listener (net.Listener) for TLS connections.
|
||||
type listener struct {
|
||||
net.Listener
|
||||
config *Config
|
||||
extraConfig *ExtraConfig
|
||||
config *Config
|
||||
}
|
||||
|
||||
// Accept waits for and returns the next incoming TLS connection.
|
||||
@@ -70,18 +67,17 @@ func (l *listener) Accept() (net.Conn, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return Server(c, l.config, l.extraConfig), nil
|
||||
return Server(c, l.config), nil
|
||||
}
|
||||
|
||||
// NewListener creates a Listener which accepts connections from an inner
|
||||
// Listener and wraps each connection with Server.
|
||||
// The configuration config must be non-nil and must include
|
||||
// at least one certificate or else set GetCertificate.
|
||||
func NewListener(inner net.Listener, config *Config, extraConfig *ExtraConfig) net.Listener {
|
||||
func NewListener(inner net.Listener, config *Config) net.Listener {
|
||||
l := new(listener)
|
||||
l.Listener = inner
|
||||
l.config = config
|
||||
l.extraConfig = extraConfig
|
||||
return l
|
||||
}
|
||||
|
||||
@@ -89,7 +85,7 @@ func NewListener(inner net.Listener, config *Config, extraConfig *ExtraConfig) n
|
||||
// given network address using net.Listen.
|
||||
// The configuration config must be non-nil and must include
|
||||
// at least one certificate or else set GetCertificate.
|
||||
func Listen(network, laddr string, config *Config, extraConfig *ExtraConfig) (net.Listener, error) {
|
||||
func Listen(network, laddr string, config *Config) (net.Listener, error) {
|
||||
if config == nil || len(config.Certificates) == 0 &&
|
||||
config.GetCertificate == nil && config.GetConfigForClient == nil {
|
||||
return nil, errors.New("tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config")
|
||||
@@ -98,7 +94,7 @@ func Listen(network, laddr string, config *Config, extraConfig *ExtraConfig) (ne
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewListener(l, config, extraConfig), nil
|
||||
return NewListener(l, config), nil
|
||||
}
|
||||
|
||||
type timeoutError struct{}
|
||||
@@ -117,11 +113,11 @@ func (timeoutError) Temporary() bool { return true }
|
||||
//
|
||||
// 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 DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
|
||||
return dial(context.Background(), dialer, network, addr, config)
|
||||
}
|
||||
|
||||
func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config, extraConfig *ExtraConfig) (*Conn, error) {
|
||||
func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
|
||||
if netDialer.Timeout != 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout)
|
||||
@@ -157,7 +153,7 @@ func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, conf
|
||||
config = c
|
||||
}
|
||||
|
||||
conn := Client(rawConn, config, extraConfig)
|
||||
conn := Client(rawConn, config)
|
||||
if err := conn.HandshakeContext(ctx); err != nil {
|
||||
rawConn.Close()
|
||||
return nil, err
|
||||
@@ -171,8 +167,8 @@ func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, conf
|
||||
// Dial interprets a nil configuration as equivalent to
|
||||
// the zero configuration; see the documentation of Config
|
||||
// for the defaults.
|
||||
func Dial(network, addr string, config *Config, extraConfig *ExtraConfig) (*Conn, error) {
|
||||
return DialWithDialer(new(net.Dialer), network, addr, config, extraConfig)
|
||||
func Dial(network, addr string, config *Config) (*Conn, error) {
|
||||
return DialWithDialer(new(net.Dialer), network, addr, config)
|
||||
}
|
||||
|
||||
// Dialer dials TLS connections given a configuration and a Dialer for the
|
||||
@@ -188,8 +184,6 @@ type Dialer struct {
|
||||
// configuration; see the documentation of Config for the
|
||||
// defaults.
|
||||
Config *Config
|
||||
|
||||
ExtraConfig *ExtraConfig
|
||||
}
|
||||
|
||||
// Dial connects to the given network address and initiates a TLS
|
||||
@@ -220,7 +214,7 @@ func (d *Dialer) netDialer() *net.Dialer {
|
||||
//
|
||||
// The returned Conn, if any, will always be of type *Conn.
|
||||
func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
c, err := dial(ctx, d.netDialer(), network, addr, d.Config, d.ExtraConfig)
|
||||
c, err := dial(ctx, d.netDialer(), network, addr, d.Config)
|
||||
if err != nil {
|
||||
// Don't return c (a typed nil) in an interface.
|
||||
return nil, err
|
||||
|
||||
5
vendor/github.com/quic-go/qtls-go1-20/unsafe.go
generated
vendored
5
vendor/github.com/quic-go/qtls-go1-20/unsafe.go
generated
vendored
@@ -94,3 +94,8 @@ func compareStruct(a, b reflect.Type) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// InitSessionTicketKeys triggers the initialization of session ticket keys.
|
||||
func InitSessionTicketKeys(conf *Config) {
|
||||
fromConfig(conf).ticketKeys(nil)
|
||||
}
|
||||
|
||||
2
vendor/github.com/quic-go/quic-go/.golangci.yml
generated
vendored
2
vendor/github.com/quic-go/quic-go/.golangci.yml
generated
vendored
@@ -1,4 +1,6 @@
|
||||
run:
|
||||
skip-files:
|
||||
- internal/handshake/cipher_suite.go
|
||||
linters-settings:
|
||||
depguard:
|
||||
type: blacklist
|
||||
|
||||
217
vendor/github.com/quic-go/quic-go/README.md
generated
vendored
217
vendor/github.com/quic-go/quic-go/README.md
generated
vendored
@@ -4,29 +4,210 @@
|
||||
|
||||
[](https://pkg.go.dev/github.com/quic-go/quic-go)
|
||||
[](https://codecov.io/gh/quic-go/quic-go/)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:quic-go)
|
||||
|
||||
quic-go is an implementation of the QUIC protocol ([RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000), [RFC 9001](https://datatracker.ietf.org/doc/html/rfc9001), [RFC 9002](https://datatracker.ietf.org/doc/html/rfc9002)) in Go, including the Unreliable Datagram Extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221)) and Datagram Packetization Layer Path MTU
|
||||
Discovery (DPLPMTUD, [RFC 8899](https://datatracker.ietf.org/doc/html/rfc8899)). It has support for HTTP/3 ([RFC 9114](https://datatracker.ietf.org/doc/html/rfc9114)), including QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)).
|
||||
quic-go is an implementation of the QUIC protocol ([RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000), [RFC 9001](https://datatracker.ietf.org/doc/html/rfc9001), [RFC 9002](https://datatracker.ietf.org/doc/html/rfc9002)) in Go. It has support for HTTP/3 ([RFC 9114](https://datatracker.ietf.org/doc/html/rfc9114)), including QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)).
|
||||
|
||||
In addition to the RFCs listed above, it currently implements the [IETF QUIC draft-29](https://tools.ietf.org/html/draft-ietf-quic-transport-29). Support for draft-29 will eventually be dropped, as it is phased out of the ecosystem.
|
||||
In addition to these base RFCs, it also implements the following RFCs:
|
||||
* Unreliable Datagram Extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221))
|
||||
* Datagram Packetization Layer Path MTU Discovery (DPLPMTUD, [RFC 8899](https://datatracker.ietf.org/doc/html/rfc8899))
|
||||
* QUIC Version 2 ([RFC 9369](https://datatracker.ietf.org/doc/html/rfc9369))
|
||||
* QUIC Event Logging using qlog ([draft-ietf-quic-qlog-main-schema](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-main-schema/) and [draft-ietf-quic-qlog-quic-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-quic-events/))
|
||||
|
||||
## Guides
|
||||
Support for WebTransport over HTTP/3 ([draft-ietf-webtrans-http3](https://datatracker.ietf.org/doc/draft-ietf-webtrans-http3/)) is implemented in [webtransport-go](https://github.com/quic-go/webtransport-go).
|
||||
|
||||
*We currently support Go 1.19.x and Go 1.20.x*
|
||||
## Using QUIC
|
||||
|
||||
Running tests:
|
||||
### Running a Server
|
||||
|
||||
go test ./...
|
||||
The central entry point is the `quic.Transport`. A transport manages QUIC connections running on a single UDP socket. Since QUIC uses Connection IDs, it can demultiplex a listener (accepting incoming connections) and an arbitrary number of outgoing QUIC connections on the same UDP socket.
|
||||
|
||||
### QUIC without HTTP/3
|
||||
```go
|
||||
udpConn, err := net.ListenUDP("udp4", &net.UDPAddr{Port: 1234})
|
||||
// ... error handling
|
||||
tr := quic.Transport{
|
||||
Conn: udpConn,
|
||||
}
|
||||
ln, err := tr.Listen(tlsConf, quicConf)
|
||||
// ... error handling
|
||||
go func() {
|
||||
for {
|
||||
conn, err := ln.Accept()
|
||||
// ... error handling
|
||||
// handle the connection, usually in a new Go routine
|
||||
}
|
||||
}()
|
||||
```
|
||||
|
||||
Take a look at [this echo example](example/echo/echo.go).
|
||||
The listener `ln` can now be used to accept incoming QUIC connections by (repeatedly) calling the `Accept` method (see below for more information on the `quic.Connection`).
|
||||
|
||||
## Usage
|
||||
As a shortcut, `quic.Listen` and `quic.ListenAddr` can be used without explicitly initializing a `quic.Transport`:
|
||||
|
||||
```
|
||||
ln, err := quic.Listen(udpConn, tlsConf, quicConf)
|
||||
```
|
||||
|
||||
When using the shortcut, it's not possible to reuse the same UDP socket for outgoing connections.
|
||||
|
||||
### Running a Client
|
||||
|
||||
As mentioned above, multiple outgoing connections can share a single UDP socket, since QUIC uses Connection IDs to demultiplex connections.
|
||||
|
||||
```go
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) // 3s handshake timeout
|
||||
defer cancel()
|
||||
conn, err := tr.Dial(ctx, <server address>, <tls.Config>, <quic.Config>)
|
||||
// ... error handling
|
||||
```
|
||||
|
||||
As a shortcut, `quic.Dial` and `quic.DialAddr` can be used without explictly initializing a `quic.Transport`:
|
||||
|
||||
```go
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) // 3s handshake timeout
|
||||
defer cancel()
|
||||
conn, err := quic.Dial(ctx, conn, <server address>, <tls.Config>, <quic.Config>)
|
||||
```
|
||||
|
||||
Just as we saw before when used a similar shortcut to run a server, it's also not possible to reuse the same UDP socket for other outgoing connections, or to listen for incoming connections.
|
||||
|
||||
### Using a QUIC Connection
|
||||
|
||||
#### Accepting Streams
|
||||
|
||||
QUIC is a stream-multiplexed transport. A `quic.Connection` fundamentally differs from the `net.Conn` and the `net.PacketConn` interface defined in the standard library. Data is sent and received on (unidirectional and bidirectional) streams (and, if supported, in [datagrams](#quic-datagrams)), not on the connection itself. The stream state machine is described in detail in [Section 3 of RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000#section-3).
|
||||
|
||||
Note: A unidirectional stream is a stream that the initiator can only write to (`quic.SendStream`), and the receiver can only read from (`quic.ReceiveStream`). A bidirectional stream (`quic.Stream`) allows reading from and writing to for both sides.
|
||||
|
||||
On the receiver side, streams are accepted using the `AcceptStream` (for bidirectional) and `AcceptUniStream` functions. For most user cases, it makes sense to call these functions in a loop:
|
||||
|
||||
```go
|
||||
for {
|
||||
str, err := conn.AcceptStream(context.Background()) // for bidirectional streams
|
||||
// ... error handling
|
||||
// handle the stream, usually in a new Go routine
|
||||
}
|
||||
```
|
||||
|
||||
These functions return an error when the underlying QUIC connection is closed.
|
||||
|
||||
#### Opening Streams
|
||||
|
||||
There are two slightly different ways to open streams, one synchronous and one (potentially) asynchronous. This API is necessary since the receiver grants us a certain number of streams that we're allowed to open. It may grant us additional streams later on (typically when existing streams are closed), but it means that at the time we want to open a new stream, we might not be able to do so.
|
||||
|
||||
Using the synchronous method `OpenStreamSync` for bidirectional streams, and `OpenUniStreamSync` for unidirectional streams, an application can block until the peer allows opening additional streams. In case that we're allowed to open a new stream, these methods return right away:
|
||||
|
||||
```go
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
str, err := conn.OpenStreamSync(ctx) // wait up to 5s to open a new bidirectional stream
|
||||
```
|
||||
|
||||
The asynchronous version never blocks. If it's currently not possible to open a new stream, it returns a `net.Error` timeout error:
|
||||
|
||||
```go
|
||||
str, err := conn.OpenStream()
|
||||
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
|
||||
// It's currently not possible to open another stream,
|
||||
// but it might be possible later, once the peer allowed us to do so.
|
||||
}
|
||||
```
|
||||
|
||||
These functions return an error when the underlying QUIC connection is closed.
|
||||
|
||||
#### Using Streams
|
||||
|
||||
Using QUIC streams is pretty straightforward. The `quic.ReceiveStream` implements the `io.Reader` interface, and the `quic.SendStream` implements the `io.Writer` interface. A bidirectional stream (`quic.Stream`) implements both these interfaces. Conceptually, a bidirectional stream can be thought of as the composition of two unidirectional streams in opposite directions.
|
||||
|
||||
Calling `Close` on a `quic.SendStream` or a `quic.Stream` closes the send side of the stream. On the receiver side, this will be surfaced as an `io.EOF` returned from the `io.Reader` once all data has been consumed. Note that for bidirectional streams, `Close` _only_ closes the send side of the stream. It is still possible to read from the stream until the peer closes or resets the stream.
|
||||
|
||||
In case the application wishes to abort sending on a `quic.SendStream` or a `quic.Stream` , it can reset the send side by calling `CancelWrite` with an application-defined error code (an unsigned 62-bit number). On the receiver side, this surfaced as a `quic.StreamError` containing that error code on the `io.Reader`. Note that for bidirectional streams, `CancelWrite` _only_ resets the send side of the stream. It is still possible to read from the stream until the peer closes or resets the stream.
|
||||
|
||||
Conversely, in case the application wishes to abort receiving from a `quic.ReceiveStream` or a `quic.Stream`, it can ask the sender to abort data transmission by calling `CancelRead` with an application-defined error code (an unsigned 62-bit number). On the receiver side, this surfaced as a `quic.StreamError` containing that error code on the `io.Writer`. Note that for bidirectional streams, `CancelWrite` _only_ resets the receive side of the stream. It is still possible to write to the stream.
|
||||
|
||||
A bidirectional stream is only closed once both the read and the write side of the stream have been either closed or reset. Only then the peer is granted a new stream according to the maximum number of concurrent streams configured via `quic.Config.MaxIncomingStreams`.
|
||||
|
||||
### Configuring QUIC
|
||||
|
||||
The `quic.Config` struct passed to both the listen and dial calls (see above) contains a wide range of configuration options for QUIC connections, incl. the ability to fine-tune flow control limits, the number of streams that the peer is allowed to open concurrently, keep-alives, idle timeouts, and many more. Please refer to the documentation for the `quic.Config` for details.
|
||||
|
||||
The `quic.Transport` contains a few configuration options that don't apply to any single QUIC connection, but to all connections handled by that transport. It is highly recommend to set the `StatelessResetToken`, which allows endpoints to quickly recover from crashes / reboots of our node (see [Section 10.3 of RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000#section-10.3)).
|
||||
|
||||
### Closing a Connection
|
||||
|
||||
#### When the remote Peer closes the Connection
|
||||
|
||||
In case the peer closes the QUIC connection, all calls to open streams, accept streams, as well as all methods on streams immediately return an error. Additionally, it is set as cancellation cause of the connection context. Users can use errors assertions to find out what exactly went wrong:
|
||||
|
||||
* `quic.VersionNegotiationError`: Happens during the handshake, if there is no overlap between our and the remote's supported QUIC versions.
|
||||
* `quic.HandshakeTimeoutError`: Happens if the QUIC handshake doesn't complete within the time specified in `quic.Config.HandshakeTimeout`.
|
||||
* `quic.IdleTimeoutError`: Happens after completion of the handshake if the connection is idle for longer than the minimum of both peers idle timeouts (as configured by `quic.Config.IdleTimeout`). The connection is considered idle when no stream data (and datagrams, if applicable) are exchanged for that period. The QUIC connection can be instructed to regularly send a packet to prevent a connection from going idle by setting `quic.Config.KeepAlive`. However, this is no guarantee that the peer doesn't suddenly go away (e.g. by abruptly shutting down the node or by crashing), or by a NAT binding expiring, in which case this error might still occur.
|
||||
* `quic.StatelessResetError`: Happens when the remote peer lost the state required to decrypt the packet. This requires the `quic.Transport.StatelessResetToken` to be configured by the peer.
|
||||
* `quic.TransportError`: Happens if when the QUIC protocol is violated. Unless the error code is `APPLICATION_ERROR`, this will not happen unless one of the QUIC stacks involved is misbehaving. Please open an issue if you encounter this error.
|
||||
* `quic.ApplicationError`: Happens when the remote decides to close the connection, see below.
|
||||
|
||||
#### Initiated by the Application
|
||||
|
||||
A `quic.Connection` can be closed using `CloseWithError`:
|
||||
|
||||
```go
|
||||
conn.CloseWithError(0x42, "error 0x42 occurred")
|
||||
```
|
||||
|
||||
Applications can transmit both an error code (an unsigned 62-bit number) as well as a UTF-8 encoded human-readable reason. The error code allows the receiver to learn why the connection was closed, and the reason can be useful for debugging purposes.
|
||||
|
||||
On the receiver side, this is surfaced as a `quic.ApplicationError`.
|
||||
|
||||
### QUIC Datagrams
|
||||
|
||||
Unreliable datagrams are a QUIC extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221)) that is negotiated during the handshake. Support can be enabled by setting the `quic.Config.EnableDatagram` flag. Note that this doesn't guarantee that the peer also supports datagrams. Whether or not the feature negotiation succeeded can be learned from the `quic.ConnectionState.SupportsDatagrams` obtained from `quic.Connection.ConnectionState()`.
|
||||
|
||||
QUIC DATAGRAMs are a new QUIC frame type sent in QUIC 1-RTT packets (i.e. after completion of the handshake). Therefore, they're end-to-end encrypted and congestion-controlled. However, if a DATAGRAM frame is deemed lost by QUIC's loss detection mechanism, they are not retransmitted.
|
||||
|
||||
Datagrams are sent using the `SendDatagram` method on the `quic.Connection`:
|
||||
|
||||
```go
|
||||
conn.SendDatagram([]byte("foobar"))
|
||||
```
|
||||
|
||||
And received using `ReceiveDatagram`:
|
||||
|
||||
```go
|
||||
msg, err := conn.ReceiveDatagram()
|
||||
```
|
||||
|
||||
Note that this code path is currently not optimized. It works for datagrams that are sent occasionally, but it doesn't achieve the same throughput as writing data on a stream. Please get in touch on issue #3766 if your use case relies on high datagram throughput, or if you'd like to help fix this issue. There are also some restrictions regarding the maximum message size (see #3599).
|
||||
|
||||
### QUIC Event Logging using qlog
|
||||
|
||||
quic-go logs a wide range of events defined in [draft-ietf-quic-qlog-quic-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-quic-events/), providing comprehensive insights in the internals of a QUIC connection.
|
||||
|
||||
qlog files can be processed by a number of 3rd-party tools. [qviz](https://qvis.quictools.info/) has proven very useful for debugging all kinds of QUIC connection failures.
|
||||
|
||||
qlog is activated by setting a `Tracer` callback on the `Config`. It is called as soon as quic-go decides to starts the QUIC handshake on a new connection.
|
||||
A useful implementation of this callback could look like this:
|
||||
```go
|
||||
quic.Config{
|
||||
Tracer: func(ctx context.Context, p logging.Perspective, connID quic.ConnectionID) *logging.ConnectionTracer {
|
||||
role := "server"
|
||||
if p == logging.PerspectiveClient {
|
||||
role = "client"
|
||||
}
|
||||
filename := fmt.Sprintf("./log_%s_%s.qlog", connID, role)
|
||||
f, err := os.Create(filename)
|
||||
// handle the error
|
||||
return qlog.NewConnectionTracer(f, p, connID)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This implementation of the callback creates a new qlog file in the current directory named `log_<client / server>_<QUIC connection ID>.qlog`.
|
||||
|
||||
|
||||
## Using HTTP/3
|
||||
|
||||
### As a server
|
||||
|
||||
See the [example server](example/main.go). Starting a QUIC server is very similar to the standard lib http in go:
|
||||
See the [example server](example/main.go). Starting a QUIC server is very similar to the standard library http package in Go:
|
||||
|
||||
```go
|
||||
http.Handle("/", http.FileServer(http.Dir(wwwDir)))
|
||||
@@ -46,12 +227,13 @@ http.Client{
|
||||
## Projects using quic-go
|
||||
|
||||
| Project | Description | Stars |
|
||||
|-----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|
|
||||
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
|
||||
| [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) | Free and open source, powerful network-wide ads & trackers blocking DNS server. |  |
|
||||
| [algernon](https://github.com/xyproto/algernon) | Small self-contained pure-Go web server with Lua, Markdown, HTTP/2, QUIC, Redis and PostgreSQL support |  |
|
||||
| [caddy](https://github.com/caddyserver/caddy/) | Fast, multi-platform web server with automatic HTTPS |  |
|
||||
| [cloudflared](https://github.com/cloudflare/cloudflared) | A tunneling daemon that proxies traffic from the Cloudflare network to your origins |  |
|
||||
| [go-libp2p](https://github.com/libp2p/go-libp2p) | libp2p implementation in Go, powering [Kubo](https://github.com/ipfs/kubo) (IPFS) and [Lotus](https://github.com/filecoin-project/lotus) (Filecoin), among others |  |
|
||||
| [Hysteria](https://github.com/apernet/hysteria) | A powerful, lightning fast and censorship resistant proxy |  |
|
||||
| [Mercure](https://github.com/dunglas/mercure) | An open, easy, fast, reliable and battery-efficient solution for real-time communications |  |
|
||||
| [OONI Probe](https://github.com/ooni/probe-cli) | Next generation OONI Probe. Library and CLI tool. |  |
|
||||
| [syncthing](https://github.com/syncthing/syncthing/) | Open Source Continuous File Synchronization |  |
|
||||
@@ -59,6 +241,17 @@ http.Client{
|
||||
| [v2ray-core](https://github.com/v2fly/v2ray-core) | A platform for building proxies to bypass network restrictions |  |
|
||||
| [YoMo](https://github.com/yomorun/yomo) | Streaming Serverless Framework for Geo-distributed System |  |
|
||||
|
||||
If you'd like to see your project added to this list, please send us a PR.
|
||||
|
||||
## Release Policy
|
||||
|
||||
quic-go always aims to support the latest two Go releases.
|
||||
|
||||
### Dependency on forked crypto/tls
|
||||
|
||||
Since the standard library didn't provide any QUIC APIs before the Go 1.21 release, we had to fork crypto/tls to add the required APIs ourselves: [qtls for Go 1.20](https://github.com/quic-go/qtls-go1-20).
|
||||
This had led to a lot of pain in the Go ecosystem, and we're happy that we can rely on Go 1.21 going forward.
|
||||
|
||||
## Contributing
|
||||
|
||||
We are always happy to welcome new contributors! We have a number of self-contained issues that are suitable for first-time contributors, they are tagged with [help wanted](https://github.com/quic-go/quic-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). If you have any questions, please feel free to reach out by opening an issue or leaving a comment.
|
||||
|
||||
34
vendor/github.com/quic-go/quic-go/buffer_pool.go
generated
vendored
34
vendor/github.com/quic-go/quic-go/buffer_pool.go
generated
vendored
@@ -51,18 +51,22 @@ func (b *packetBuffer) Release() {
|
||||
}
|
||||
|
||||
// Len returns the length of Data
|
||||
func (b *packetBuffer) Len() protocol.ByteCount {
|
||||
return protocol.ByteCount(len(b.Data))
|
||||
}
|
||||
func (b *packetBuffer) Len() protocol.ByteCount { return protocol.ByteCount(len(b.Data)) }
|
||||
func (b *packetBuffer) Cap() protocol.ByteCount { return protocol.ByteCount(cap(b.Data)) }
|
||||
|
||||
func (b *packetBuffer) putBack() {
|
||||
if cap(b.Data) != int(protocol.MaxPacketBufferSize) {
|
||||
panic("putPacketBuffer called with packet of wrong size!")
|
||||
if cap(b.Data) == protocol.MaxPacketBufferSize {
|
||||
bufferPool.Put(b)
|
||||
return
|
||||
}
|
||||
bufferPool.Put(b)
|
||||
if cap(b.Data) == protocol.MaxLargePacketBufferSize {
|
||||
largeBufferPool.Put(b)
|
||||
return
|
||||
}
|
||||
panic("putPacketBuffer called with packet of wrong size!")
|
||||
}
|
||||
|
||||
var bufferPool sync.Pool
|
||||
var bufferPool, largeBufferPool sync.Pool
|
||||
|
||||
func getPacketBuffer() *packetBuffer {
|
||||
buf := bufferPool.Get().(*packetBuffer)
|
||||
@@ -71,10 +75,18 @@ func getPacketBuffer() *packetBuffer {
|
||||
return buf
|
||||
}
|
||||
|
||||
func getLargePacketBuffer() *packetBuffer {
|
||||
buf := largeBufferPool.Get().(*packetBuffer)
|
||||
buf.refCount = 1
|
||||
buf.Data = buf.Data[:0]
|
||||
return buf
|
||||
}
|
||||
|
||||
func init() {
|
||||
bufferPool.New = func() interface{} {
|
||||
return &packetBuffer{
|
||||
Data: make([]byte, 0, protocol.MaxPacketBufferSize),
|
||||
}
|
||||
bufferPool.New = func() any {
|
||||
return &packetBuffer{Data: make([]byte, 0, protocol.MaxPacketBufferSize)}
|
||||
}
|
||||
largeBufferPool.New = func() any {
|
||||
return &packetBuffer{Data: make([]byte, 0, protocol.MaxLargePacketBufferSize)}
|
||||
}
|
||||
}
|
||||
|
||||
45
vendor/github.com/quic-go/quic-go/client.go
generated
vendored
45
vendor/github.com/quic-go/quic-go/client.go
generated
vendored
@@ -34,7 +34,7 @@ type client struct {
|
||||
|
||||
conn quicConn
|
||||
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
tracingID uint64
|
||||
logger utils.Logger
|
||||
}
|
||||
@@ -43,7 +43,9 @@ type client struct {
|
||||
var generateConnectionIDForInitial = protocol.GenerateConnectionIDForInitial
|
||||
|
||||
// DialAddr establishes a new QUIC connection to a server.
|
||||
// It uses a new UDP connection and closes this connection when the QUIC connection is closed.
|
||||
// It resolves the address, and then creates a new UDP connection to dial the QUIC server.
|
||||
// When the QUIC connection is closed, this UDP connection is closed.
|
||||
// See Dial for more details.
|
||||
func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (Connection, error) {
|
||||
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
@@ -53,15 +55,15 @@ func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Confi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl, err := setupTransport(udpConn, tlsConf, true)
|
||||
tr, err := setupTransport(udpConn, tlsConf, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dl.Dial(ctx, udpAddr, tlsConf, conf)
|
||||
return tr.dial(ctx, udpAddr, addr, tlsConf, conf, false)
|
||||
}
|
||||
|
||||
// DialAddrEarly establishes a new 0-RTT QUIC connection to a server.
|
||||
// It uses a new UDP connection and closes this connection when the QUIC connection is closed.
|
||||
// See DialAddr for more details.
|
||||
func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) {
|
||||
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
@@ -71,20 +73,20 @@ func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl, err := setupTransport(udpConn, tlsConf, true)
|
||||
tr, err := setupTransport(udpConn, tlsConf, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := dl.DialEarly(ctx, udpAddr, tlsConf, conf)
|
||||
conn, err := tr.dial(ctx, udpAddr, addr, tlsConf, conf, true)
|
||||
if err != nil {
|
||||
dl.Close()
|
||||
tr.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn using the provided context.
|
||||
// See DialEarly for details.
|
||||
// DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn.
|
||||
// See Dial for more details.
|
||||
func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) {
|
||||
dl, err := setupTransport(c, tlsConf, false)
|
||||
if err != nil {
|
||||
@@ -98,12 +100,15 @@ func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tl
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Dial establishes a new QUIC connection to a server using a net.PacketConn. If
|
||||
// the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn
|
||||
// does), ECN and packet info support will be enabled. In this case, ReadMsgUDP
|
||||
// and WriteMsgUDP will be used instead of ReadFrom and WriteTo to read/write
|
||||
// packets.
|
||||
// Dial establishes a new QUIC connection to a server using a net.PacketConn.
|
||||
// If the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn does),
|
||||
// ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP
|
||||
// will be used instead of ReadFrom and WriteTo to read/write packets.
|
||||
// The tls.Config must define an application protocol (using NextProtos).
|
||||
//
|
||||
// This is a convenience function. More advanced use cases should instantiate a Transport,
|
||||
// which offers configuration options for a more fine-grained control of the connection establishment,
|
||||
// including reusing the underlying UDP socket for multiple QUIC connections.
|
||||
func Dial(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) {
|
||||
dl, err := setupTransport(c, tlsConf, false)
|
||||
if err != nil {
|
||||
@@ -148,7 +153,7 @@ func dial(
|
||||
if c.config.Tracer != nil {
|
||||
c.tracer = c.config.Tracer(context.WithValue(ctx, ConnectionTracingKey, c.tracingID), protocol.PerspectiveClient, c.destConnID)
|
||||
}
|
||||
if c.tracer != nil {
|
||||
if c.tracer != nil && c.tracer.StartedConnection != nil {
|
||||
c.tracer.StartedConnection(c.sendConn.LocalAddr(), c.sendConn.RemoteAddr(), c.srcConnID, c.destConnID)
|
||||
}
|
||||
if err := c.dial(ctx); err != nil {
|
||||
@@ -158,12 +163,6 @@ func dial(
|
||||
}
|
||||
|
||||
func newClient(sendConn sendConn, connIDGenerator ConnectionIDGenerator, config *Config, tlsConf *tls.Config, onClose func(), use0RTT bool) (*client, error) {
|
||||
if tlsConf == nil {
|
||||
tlsConf = &tls.Config{}
|
||||
} else {
|
||||
tlsConf = tlsConf.Clone()
|
||||
}
|
||||
|
||||
srcConnID, err := connIDGenerator.GenerateConnectionID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -234,7 +233,7 @@ func (c *client) dial(ctx context.Context) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
c.conn.shutdown()
|
||||
return ctx.Err()
|
||||
return context.Cause(ctx)
|
||||
case err := <-errorChan:
|
||||
return err
|
||||
case recreateErr := <-recreateChan:
|
||||
|
||||
8
vendor/github.com/quic-go/quic-go/closed_conn.go
generated
vendored
8
vendor/github.com/quic-go/quic-go/closed_conn.go
generated
vendored
@@ -16,13 +16,13 @@ type closedLocalConn struct {
|
||||
perspective protocol.Perspective
|
||||
logger utils.Logger
|
||||
|
||||
sendPacket func(net.Addr, *packetInfo)
|
||||
sendPacket func(net.Addr, packetInfo)
|
||||
}
|
||||
|
||||
var _ packetHandler = &closedLocalConn{}
|
||||
|
||||
// newClosedLocalConn creates a new closedLocalConn and runs it.
|
||||
func newClosedLocalConn(sendPacket func(net.Addr, *packetInfo), pers protocol.Perspective, logger utils.Logger) packetHandler {
|
||||
func newClosedLocalConn(sendPacket func(net.Addr, packetInfo), pers protocol.Perspective, logger utils.Logger) packetHandler {
|
||||
return &closedLocalConn{
|
||||
sendPacket: sendPacket,
|
||||
perspective: pers,
|
||||
@@ -30,7 +30,7 @@ func newClosedLocalConn(sendPacket func(net.Addr, *packetInfo), pers protocol.Pe
|
||||
}
|
||||
}
|
||||
|
||||
func (c *closedLocalConn) handlePacket(p *receivedPacket) {
|
||||
func (c *closedLocalConn) handlePacket(p receivedPacket) {
|
||||
c.counter++
|
||||
// exponential backoff
|
||||
// only send a CONNECTION_CLOSE for the 1st, 2nd, 4th, 8th, 16th, ... packet arriving
|
||||
@@ -58,7 +58,7 @@ func newClosedRemoteConn(pers protocol.Perspective) packetHandler {
|
||||
return &closedRemoteConn{perspective: pers}
|
||||
}
|
||||
|
||||
func (s *closedRemoteConn) handlePacket(*receivedPacket) {}
|
||||
func (s *closedRemoteConn) handlePacket(receivedPacket) {}
|
||||
func (s *closedRemoteConn) shutdown() {}
|
||||
func (s *closedRemoteConn) destroy(error) {}
|
||||
func (s *closedRemoteConn) getPerspective() protocol.Perspective { return s.perspective }
|
||||
|
||||
10
vendor/github.com/quic-go/quic-go/codecov.yml
generated
vendored
10
vendor/github.com/quic-go/quic-go/codecov.yml
generated
vendored
@@ -1,18 +1,10 @@
|
||||
coverage:
|
||||
round: nearest
|
||||
ignore:
|
||||
- streams_map_incoming_bidi.go
|
||||
- streams_map_incoming_uni.go
|
||||
- streams_map_outgoing_bidi.go
|
||||
- streams_map_outgoing_uni.go
|
||||
- http3/gzip_reader.go
|
||||
- interop/
|
||||
- internal/ackhandler/packet_linkedlist.go
|
||||
- internal/utils/byteinterval_linkedlist.go
|
||||
- internal/utils/newconnectionid_linkedlist.go
|
||||
- internal/utils/packetinterval_linkedlist.go
|
||||
- internal/handshake/cipher_suite.go
|
||||
- internal/utils/linkedlist/linkedlist.go
|
||||
- logging/null_tracer.go
|
||||
- fuzzing/
|
||||
- metrics/
|
||||
status:
|
||||
|
||||
74
vendor/github.com/quic-go/quic-go/config.go
generated
vendored
74
vendor/github.com/quic-go/quic-go/config.go
generated
vendored
@@ -1,13 +1,12 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
)
|
||||
|
||||
// Clone clones a Config
|
||||
@@ -17,18 +16,29 @@ func (c *Config) Clone() *Config {
|
||||
}
|
||||
|
||||
func (c *Config) handshakeTimeout() time.Duration {
|
||||
return utils.Max(protocol.DefaultHandshakeTimeout, 2*c.HandshakeIdleTimeout)
|
||||
return 2 * c.HandshakeIdleTimeout
|
||||
}
|
||||
|
||||
func (c *Config) maxRetryTokenAge() time.Duration {
|
||||
return c.handshakeTimeout()
|
||||
}
|
||||
|
||||
func validateConfig(config *Config) error {
|
||||
if config == nil {
|
||||
return nil
|
||||
}
|
||||
if config.MaxIncomingStreams > 1<<60 {
|
||||
return errors.New("invalid value for Config.MaxIncomingStreams")
|
||||
const maxStreams = 1 << 60
|
||||
if config.MaxIncomingStreams > maxStreams {
|
||||
config.MaxIncomingStreams = maxStreams
|
||||
}
|
||||
if config.MaxIncomingUniStreams > 1<<60 {
|
||||
return errors.New("invalid value for Config.MaxIncomingUniStreams")
|
||||
if config.MaxIncomingUniStreams > maxStreams {
|
||||
config.MaxIncomingUniStreams = maxStreams
|
||||
}
|
||||
if config.MaxStreamReceiveWindow > quicvarint.Max {
|
||||
config.MaxStreamReceiveWindow = quicvarint.Max
|
||||
}
|
||||
if config.MaxConnectionReceiveWindow > quicvarint.Max {
|
||||
config.MaxConnectionReceiveWindow = quicvarint.Max
|
||||
}
|
||||
// check that all QUIC versions are actually supported
|
||||
for _, v := range config.Versions {
|
||||
@@ -43,12 +53,6 @@ func validateConfig(config *Config) error {
|
||||
// it may be called with nil
|
||||
func populateServerConfig(config *Config) *Config {
|
||||
config = populateConfig(config)
|
||||
if config.MaxTokenAge == 0 {
|
||||
config.MaxTokenAge = protocol.TokenValidity
|
||||
}
|
||||
if config.MaxRetryTokenAge == 0 {
|
||||
config.MaxRetryTokenAge = protocol.RetryTokenValidity
|
||||
}
|
||||
if config.RequireAddressValidation == nil {
|
||||
config.RequireAddressValidation = func(net.Addr) bool { return false }
|
||||
}
|
||||
@@ -101,33 +105,25 @@ func populateConfig(config *Config) *Config {
|
||||
} else if maxIncomingUniStreams < 0 {
|
||||
maxIncomingUniStreams = 0
|
||||
}
|
||||
maxDatagrameFrameSize := config.MaxDatagramFrameSize
|
||||
if maxDatagrameFrameSize == 0 {
|
||||
maxDatagrameFrameSize = int64(protocol.DefaultMaxDatagramFrameSize)
|
||||
}
|
||||
|
||||
return &Config{
|
||||
GetConfigForClient: config.GetConfigForClient,
|
||||
Versions: versions,
|
||||
HandshakeIdleTimeout: handshakeIdleTimeout,
|
||||
MaxIdleTimeout: idleTimeout,
|
||||
MaxTokenAge: config.MaxTokenAge,
|
||||
MaxRetryTokenAge: config.MaxRetryTokenAge,
|
||||
RequireAddressValidation: config.RequireAddressValidation,
|
||||
KeepAlivePeriod: config.KeepAlivePeriod,
|
||||
InitialStreamReceiveWindow: initialStreamReceiveWindow,
|
||||
MaxStreamReceiveWindow: maxStreamReceiveWindow,
|
||||
InitialConnectionReceiveWindow: initialConnectionReceiveWindow,
|
||||
MaxConnectionReceiveWindow: maxConnectionReceiveWindow,
|
||||
AllowConnectionWindowIncrease: config.AllowConnectionWindowIncrease,
|
||||
MaxIncomingStreams: maxIncomingStreams,
|
||||
MaxIncomingUniStreams: maxIncomingUniStreams,
|
||||
TokenStore: config.TokenStore,
|
||||
EnableDatagrams: config.EnableDatagrams,
|
||||
MaxDatagramFrameSize: maxDatagrameFrameSize,
|
||||
DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
|
||||
DisableVersionNegotiationPackets: config.DisableVersionNegotiationPackets,
|
||||
Allow0RTT: config.Allow0RTT,
|
||||
Tracer: config.Tracer,
|
||||
GetConfigForClient: config.GetConfigForClient,
|
||||
Versions: versions,
|
||||
HandshakeIdleTimeout: handshakeIdleTimeout,
|
||||
MaxIdleTimeout: idleTimeout,
|
||||
RequireAddressValidation: config.RequireAddressValidation,
|
||||
KeepAlivePeriod: config.KeepAlivePeriod,
|
||||
InitialStreamReceiveWindow: initialStreamReceiveWindow,
|
||||
MaxStreamReceiveWindow: maxStreamReceiveWindow,
|
||||
InitialConnectionReceiveWindow: initialConnectionReceiveWindow,
|
||||
MaxConnectionReceiveWindow: maxConnectionReceiveWindow,
|
||||
AllowConnectionWindowIncrease: config.AllowConnectionWindowIncrease,
|
||||
MaxIncomingStreams: maxIncomingStreams,
|
||||
MaxIncomingUniStreams: maxIncomingUniStreams,
|
||||
TokenStore: config.TokenStore,
|
||||
EnableDatagrams: config.EnableDatagrams,
|
||||
DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
|
||||
Allow0RTT: config.Allow0RTT,
|
||||
Tracer: config.Tracer,
|
||||
}
|
||||
}
|
||||
|
||||
986
vendor/github.com/quic-go/quic-go/connection.go
generated
vendored
986
vendor/github.com/quic-go/quic-go/connection.go
generated
vendored
File diff suppressed because it is too large
Load Diff
14
vendor/github.com/quic-go/quic-go/crypto_stream.go
generated
vendored
14
vendor/github.com/quic-go/quic-go/crypto_stream.go
generated
vendored
@@ -71,17 +71,9 @@ func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error {
|
||||
|
||||
// GetCryptoData retrieves data that was received in CRYPTO frames
|
||||
func (s *cryptoStreamImpl) GetCryptoData() []byte {
|
||||
if len(s.msgBuf) < 4 {
|
||||
return nil
|
||||
}
|
||||
msgLen := 4 + int(s.msgBuf[1])<<16 + int(s.msgBuf[2])<<8 + int(s.msgBuf[3])
|
||||
if len(s.msgBuf) < msgLen {
|
||||
return nil
|
||||
}
|
||||
msg := make([]byte, msgLen)
|
||||
copy(msg, s.msgBuf[:msgLen])
|
||||
s.msgBuf = s.msgBuf[msgLen:]
|
||||
return msg
|
||||
b := s.msgBuf
|
||||
s.msgBuf = nil
|
||||
return b
|
||||
}
|
||||
|
||||
func (s *cryptoStreamImpl) Finish() error {
|
||||
|
||||
35
vendor/github.com/quic-go/quic-go/crypto_stream_manager.go
generated
vendored
35
vendor/github.com/quic-go/quic-go/crypto_stream_manager.go
generated
vendored
@@ -3,12 +3,14 @@ package quic
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/handshake"
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
type cryptoDataHandler interface {
|
||||
HandleMessage([]byte, protocol.EncryptionLevel) bool
|
||||
HandleMessage([]byte, protocol.EncryptionLevel) error
|
||||
NextEvent() handshake.Event
|
||||
}
|
||||
|
||||
type cryptoStreamManager struct {
|
||||
@@ -33,7 +35,7 @@ func newCryptoStreamManager(
|
||||
}
|
||||
}
|
||||
|
||||
func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) (bool /* encryption level changed */, error) {
|
||||
func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) error {
|
||||
var str cryptoStream
|
||||
//nolint:exhaustive // CRYPTO frames cannot be sent in 0-RTT packets.
|
||||
switch encLevel {
|
||||
@@ -44,18 +46,37 @@ func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLeve
|
||||
case protocol.Encryption1RTT:
|
||||
str = m.oneRTTStream
|
||||
default:
|
||||
return false, fmt.Errorf("received CRYPTO frame with unexpected encryption level: %s", encLevel)
|
||||
return fmt.Errorf("received CRYPTO frame with unexpected encryption level: %s", encLevel)
|
||||
}
|
||||
if err := str.HandleCryptoFrame(frame); err != nil {
|
||||
return false, err
|
||||
return err
|
||||
}
|
||||
for {
|
||||
data := str.GetCryptoData()
|
||||
if data == nil {
|
||||
return false, nil
|
||||
return nil
|
||||
}
|
||||
if encLevelFinished := m.cryptoHandler.HandleMessage(data, encLevel); encLevelFinished {
|
||||
return true, str.Finish()
|
||||
if err := m.cryptoHandler.HandleMessage(data, encLevel); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *cryptoStreamManager) GetPostHandshakeData(maxSize protocol.ByteCount) *wire.CryptoFrame {
|
||||
if !m.oneRTTStream.HasData() {
|
||||
return nil
|
||||
}
|
||||
return m.oneRTTStream.PopCryptoFrame(maxSize)
|
||||
}
|
||||
|
||||
func (m *cryptoStreamManager) Drop(encLevel protocol.EncryptionLevel) error {
|
||||
//nolint:exhaustive // 1-RTT keys should never get dropped.
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
return m.initialStream.Finish()
|
||||
case protocol.EncryptionHandshake:
|
||||
return m.handshakeStream.Finish()
|
||||
default:
|
||||
panic(fmt.Sprintf("dropped unexpected encryption level: %s", encLevel))
|
||||
}
|
||||
}
|
||||
|
||||
5
vendor/github.com/quic-go/quic-go/datagram_queue.go
generated
vendored
5
vendor/github.com/quic-go/quic-go/datagram_queue.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
@@ -98,7 +99,7 @@ func (h *datagramQueue) HandleDatagramFrame(f *wire.DatagramFrame) {
|
||||
}
|
||||
|
||||
// Receive gets a received DATAGRAM frame.
|
||||
func (h *datagramQueue) Receive() ([]byte, error) {
|
||||
func (h *datagramQueue) Receive(ctx context.Context) ([]byte, error) {
|
||||
for {
|
||||
h.rcvMx.Lock()
|
||||
if len(h.rcvQueue) > 0 {
|
||||
@@ -113,6 +114,8 @@ func (h *datagramQueue) Receive() ([]byte, error) {
|
||||
continue
|
||||
case <-h.closed:
|
||||
return nil, h.closeErr
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
vendor/github.com/quic-go/quic-go/errors.go
generated
vendored
12
vendor/github.com/quic-go/quic-go/errors.go
generated
vendored
@@ -61,3 +61,15 @@ func (e *StreamError) Error() string {
|
||||
}
|
||||
return fmt.Sprintf("stream %d canceled by %s with error code %d", e.StreamID, pers, e.ErrorCode)
|
||||
}
|
||||
|
||||
// DatagramTooLargeError is returned from Connection.SendDatagram if the payload is too large to be sent.
|
||||
type DatagramTooLargeError struct {
|
||||
PeerMaxDatagramFrameSize int64
|
||||
}
|
||||
|
||||
func (e *DatagramTooLargeError) Is(target error) bool {
|
||||
_, ok := target.(*DatagramTooLargeError)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (e *DatagramTooLargeError) Error() string { return "DATAGRAM frame too large" }
|
||||
|
||||
49
vendor/github.com/quic-go/quic-go/framer.go
generated
vendored
49
vendor/github.com/quic-go/quic-go/framer.go
generated
vendored
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/quic-go/quic-go/internal/ackhandler"
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils/ringbuffer"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
)
|
||||
@@ -14,10 +15,10 @@ type framer interface {
|
||||
HasData() bool
|
||||
|
||||
QueueControlFrame(wire.Frame)
|
||||
AppendControlFrames([]*ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount)
|
||||
AppendControlFrames([]ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]ackhandler.Frame, protocol.ByteCount)
|
||||
|
||||
AddActiveStream(protocol.StreamID)
|
||||
AppendStreamFrames([]*ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount)
|
||||
AppendStreamFrames([]ackhandler.StreamFrame, protocol.ByteCount, protocol.VersionNumber) ([]ackhandler.StreamFrame, protocol.ByteCount)
|
||||
|
||||
Handle0RTTRejection() error
|
||||
}
|
||||
@@ -28,7 +29,7 @@ type framerI struct {
|
||||
streamGetter streamGetter
|
||||
|
||||
activeStreams map[protocol.StreamID]struct{}
|
||||
streamQueue []protocol.StreamID
|
||||
streamQueue ringbuffer.RingBuffer[protocol.StreamID]
|
||||
|
||||
controlFrameMutex sync.Mutex
|
||||
controlFrames []wire.Frame
|
||||
@@ -45,7 +46,7 @@ func newFramer(streamGetter streamGetter) framer {
|
||||
|
||||
func (f *framerI) HasData() bool {
|
||||
f.mutex.Lock()
|
||||
hasData := len(f.streamQueue) > 0
|
||||
hasData := !f.streamQueue.Empty()
|
||||
f.mutex.Unlock()
|
||||
if hasData {
|
||||
return true
|
||||
@@ -62,7 +63,7 @@ func (f *framerI) QueueControlFrame(frame wire.Frame) {
|
||||
f.controlFrameMutex.Unlock()
|
||||
}
|
||||
|
||||
func (f *framerI) AppendControlFrames(frames []*ackhandler.Frame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount) {
|
||||
func (f *framerI) AppendControlFrames(frames []ackhandler.Frame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]ackhandler.Frame, protocol.ByteCount) {
|
||||
var length protocol.ByteCount
|
||||
f.controlFrameMutex.Lock()
|
||||
for len(f.controlFrames) > 0 {
|
||||
@@ -71,9 +72,7 @@ func (f *framerI) AppendControlFrames(frames []*ackhandler.Frame, maxLen protoco
|
||||
if length+frameLen > maxLen {
|
||||
break
|
||||
}
|
||||
af := ackhandler.GetFrame()
|
||||
af.Frame = frame
|
||||
frames = append(frames, af)
|
||||
frames = append(frames, ackhandler.Frame{Frame: frame})
|
||||
length += frameLen
|
||||
f.controlFrames = f.controlFrames[:len(f.controlFrames)-1]
|
||||
}
|
||||
@@ -84,24 +83,23 @@ func (f *framerI) AppendControlFrames(frames []*ackhandler.Frame, maxLen protoco
|
||||
func (f *framerI) AddActiveStream(id protocol.StreamID) {
|
||||
f.mutex.Lock()
|
||||
if _, ok := f.activeStreams[id]; !ok {
|
||||
f.streamQueue = append(f.streamQueue, id)
|
||||
f.streamQueue.PushBack(id)
|
||||
f.activeStreams[id] = struct{}{}
|
||||
}
|
||||
f.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (f *framerI) AppendStreamFrames(frames []*ackhandler.Frame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]*ackhandler.Frame, protocol.ByteCount) {
|
||||
func (f *framerI) AppendStreamFrames(frames []ackhandler.StreamFrame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]ackhandler.StreamFrame, protocol.ByteCount) {
|
||||
startLen := len(frames)
|
||||
var length protocol.ByteCount
|
||||
var lastFrame *ackhandler.Frame
|
||||
f.mutex.Lock()
|
||||
// pop STREAM frames, until less than MinStreamFrameSize bytes are left in the packet
|
||||
numActiveStreams := len(f.streamQueue)
|
||||
numActiveStreams := f.streamQueue.Len()
|
||||
for i := 0; i < numActiveStreams; i++ {
|
||||
if protocol.MinStreamFrameSize+length > maxLen {
|
||||
break
|
||||
}
|
||||
id := f.streamQueue[0]
|
||||
f.streamQueue = f.streamQueue[1:]
|
||||
id := f.streamQueue.PopFront()
|
||||
// This should never return an error. Better check it anyway.
|
||||
// The stream will only be in the streamQueue, if it enqueued itself there.
|
||||
str, err := f.streamGetter.GetOrOpenSendStream(id)
|
||||
@@ -115,28 +113,27 @@ func (f *framerI) AppendStreamFrames(frames []*ackhandler.Frame, maxLen protocol
|
||||
// Therefore, we can pretend to have more bytes available when popping
|
||||
// the STREAM frame (which will always have the DataLen set).
|
||||
remainingLen += quicvarint.Len(uint64(remainingLen))
|
||||
frame, hasMoreData := str.popStreamFrame(remainingLen, v)
|
||||
frame, ok, hasMoreData := str.popStreamFrame(remainingLen, v)
|
||||
if hasMoreData { // put the stream back in the queue (at the end)
|
||||
f.streamQueue = append(f.streamQueue, id)
|
||||
} else { // no more data to send. Stream is not active any more
|
||||
f.streamQueue.PushBack(id)
|
||||
} else { // no more data to send. Stream is not active
|
||||
delete(f.activeStreams, id)
|
||||
}
|
||||
// The frame can be nil
|
||||
// The frame can be "nil"
|
||||
// * if the receiveStream was canceled after it said it had data
|
||||
// * the remaining size doesn't allow us to add another STREAM frame
|
||||
if frame == nil {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
frames = append(frames, frame)
|
||||
length += frame.Length(v)
|
||||
lastFrame = frame
|
||||
length += frame.Frame.Length(v)
|
||||
}
|
||||
f.mutex.Unlock()
|
||||
if lastFrame != nil {
|
||||
lastFrameLen := lastFrame.Length(v)
|
||||
if len(frames) > startLen {
|
||||
l := frames[len(frames)-1].Frame.Length(v)
|
||||
// account for the smaller size of the last STREAM frame
|
||||
lastFrame.Frame.(*wire.StreamFrame).DataLenPresent = false
|
||||
length += lastFrame.Length(v) - lastFrameLen
|
||||
frames[len(frames)-1].Frame.DataLenPresent = false
|
||||
length += frames[len(frames)-1].Frame.Length(v) - l
|
||||
}
|
||||
return frames, length
|
||||
}
|
||||
@@ -146,7 +143,7 @@ func (f *framerI) Handle0RTTRejection() error {
|
||||
defer f.mutex.Unlock()
|
||||
|
||||
f.controlFrameMutex.Lock()
|
||||
f.streamQueue = f.streamQueue[:0]
|
||||
f.streamQueue.Clear()
|
||||
for id := range f.activeStreams {
|
||||
delete(f.activeStreams, id)
|
||||
}
|
||||
|
||||
66
vendor/github.com/quic-go/quic-go/interface.go
generated
vendored
66
vendor/github.com/quic-go/quic-go/interface.go
generated
vendored
@@ -2,6 +2,7 @@ package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
@@ -19,10 +20,9 @@ type StreamID = protocol.StreamID
|
||||
type VersionNumber = protocol.VersionNumber
|
||||
|
||||
const (
|
||||
// VersionDraft29 is IETF QUIC draft-29
|
||||
VersionDraft29 = protocol.VersionDraft29
|
||||
// Version1 is RFC 9000
|
||||
Version1 = protocol.Version1
|
||||
// Version2 is RFC 9369
|
||||
Version2 = protocol.Version2
|
||||
)
|
||||
|
||||
@@ -122,6 +122,8 @@ type SendStream interface {
|
||||
// The Context is canceled as soon as the write-side of the stream is closed.
|
||||
// This happens when Close() or CancelWrite() is called, or when the peer
|
||||
// cancels the read-side of their stream.
|
||||
// The cancellation cause is set to the error that caused the stream to
|
||||
// close, or `context.Canceled` in case the stream is closed without error.
|
||||
Context() context.Context
|
||||
// SetWriteDeadline sets the deadline for future Write calls
|
||||
// and any currently-blocked Write call.
|
||||
@@ -178,15 +180,17 @@ type Connection interface {
|
||||
// The error string will be sent to the peer.
|
||||
CloseWithError(ApplicationErrorCode, string) error
|
||||
// Context returns a context that is cancelled when the connection is closed.
|
||||
// The cancellation cause is set to the error that caused the connection to
|
||||
// close, or `context.Canceled` in case the listener is closed first.
|
||||
Context() context.Context
|
||||
// ConnectionState returns basic details about the QUIC connection.
|
||||
// Warning: This API should not be considered stable and might change soon.
|
||||
ConnectionState() ConnectionState
|
||||
|
||||
// SendMessage sends a message as a datagram, as specified in RFC 9221.
|
||||
SendMessage([]byte) error
|
||||
// ReceiveMessage gets a message received in a datagram, as specified in RFC 9221.
|
||||
ReceiveMessage() ([]byte, error)
|
||||
// SendDatagram sends a message as a datagram, as specified in RFC 9221.
|
||||
SendDatagram([]byte) error
|
||||
// ReceiveDatagram gets a message received in a datagram, as specified in RFC 9221.
|
||||
ReceiveDatagram(context.Context) ([]byte, error)
|
||||
}
|
||||
|
||||
// An EarlyConnection is a connection that is handshaking.
|
||||
@@ -198,7 +202,7 @@ type EarlyConnection interface {
|
||||
|
||||
// HandshakeComplete blocks until the handshake completes (or fails).
|
||||
// For the client, data sent before completion of the handshake is encrypted with 0-RTT keys.
|
||||
// For the serfer, data sent before completion of the handshake is encrypted with 1-RTT keys,
|
||||
// For the server, data sent before completion of the handshake is encrypted with 1-RTT keys,
|
||||
// however the client's identity is only verified once the handshake completes.
|
||||
HandshakeComplete() <-chan struct{}
|
||||
|
||||
@@ -208,6 +212,9 @@ type EarlyConnection interface {
|
||||
// StatelessResetKey is a key used to derive stateless reset tokens.
|
||||
type StatelessResetKey [32]byte
|
||||
|
||||
// TokenGeneratorKey is a key used to encrypt session resumption tokens.
|
||||
type TokenGeneratorKey = handshake.TokenProtectorKey
|
||||
|
||||
// A ConnectionID is a QUIC Connection ID, as defined in RFC 9000.
|
||||
// It is not able to handle QUIC Connection IDs longer than 20 bytes,
|
||||
// as they are allowed by RFC 8999.
|
||||
@@ -246,7 +253,8 @@ type Config struct {
|
||||
// If not set, it uses all versions available.
|
||||
Versions []VersionNumber
|
||||
// HandshakeIdleTimeout is the idle timeout before completion of the handshake.
|
||||
// Specifically, if we don't receive any packet from the peer within this time, the connection attempt is aborted.
|
||||
// If we don't receive any packet from the peer within this time, the connection attempt is aborted.
|
||||
// Additionally, if the handshake doesn't complete in twice this time, the connection attempt is also aborted.
|
||||
// If this value is zero, the timeout is set to 5 seconds.
|
||||
HandshakeIdleTimeout time.Duration
|
||||
// MaxIdleTimeout is the maximum duration that may pass without any incoming network activity.
|
||||
@@ -260,13 +268,6 @@ type Config struct {
|
||||
// See https://datatracker.ietf.org/doc/html/rfc9000#section-8 for details.
|
||||
// If not set, every client is forced to prove its remote address.
|
||||
RequireAddressValidation func(net.Addr) bool
|
||||
// MaxRetryTokenAge is the maximum age of a Retry token.
|
||||
// If not set, it defaults to 5 seconds. Only valid for a server.
|
||||
MaxRetryTokenAge time.Duration
|
||||
// MaxTokenAge is the maximum age of the token presented during the handshake,
|
||||
// for tokens that were issued on a previous connection.
|
||||
// If not set, it defaults to 24 hours. Only valid for a server.
|
||||
MaxTokenAge time.Duration
|
||||
// The TokenStore stores tokens received from the server.
|
||||
// Tokens are used to skip address validation on future connection attempts.
|
||||
// The key used to store tokens is the ServerName from the tls.Config, if set
|
||||
@@ -276,17 +277,21 @@ type Config struct {
|
||||
// If the application is consuming data quickly enough, the flow control auto-tuning algorithm
|
||||
// will increase the window up to MaxStreamReceiveWindow.
|
||||
// If this value is zero, it will default to 512 KB.
|
||||
// Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
|
||||
InitialStreamReceiveWindow uint64
|
||||
// MaxStreamReceiveWindow is the maximum stream-level flow control window for receiving data.
|
||||
// If this value is zero, it will default to 6 MB.
|
||||
// Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
|
||||
MaxStreamReceiveWindow uint64
|
||||
// InitialConnectionReceiveWindow is the initial size of the stream-level flow control window for receiving data.
|
||||
// If the application is consuming data quickly enough, the flow control auto-tuning algorithm
|
||||
// will increase the window up to MaxConnectionReceiveWindow.
|
||||
// If this value is zero, it will default to 512 KB.
|
||||
// Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
|
||||
InitialConnectionReceiveWindow uint64
|
||||
// MaxConnectionReceiveWindow is the connection-level flow control window for receiving data.
|
||||
// If this value is zero, it will default to 15 MB.
|
||||
// Values larger than the maximum varint (quicvarint.Max) will be clipped to that value.
|
||||
MaxConnectionReceiveWindow uint64
|
||||
// AllowConnectionWindowIncrease is called every time the connection flow controller attempts
|
||||
// to increase the connection flow control window.
|
||||
@@ -296,35 +301,30 @@ type Config struct {
|
||||
// in this callback.
|
||||
AllowConnectionWindowIncrease func(conn Connection, delta uint64) bool
|
||||
// MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
|
||||
// Values above 2^60 are invalid.
|
||||
// If not set, it will default to 100.
|
||||
// If set to a negative value, it doesn't allow any bidirectional streams.
|
||||
// Values larger than 2^60 will be clipped to that value.
|
||||
MaxIncomingStreams int64
|
||||
// MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open.
|
||||
// Values above 2^60 are invalid.
|
||||
// If not set, it will default to 100.
|
||||
// If set to a negative value, it doesn't allow any unidirectional streams.
|
||||
// Values larger than 2^60 will be clipped to that value.
|
||||
MaxIncomingUniStreams int64
|
||||
// KeepAlivePeriod defines whether this peer will periodically send a packet to keep the connection alive.
|
||||
// If set to 0, then no keep alive is sent. Otherwise, the keep alive is sent on that period (or at most
|
||||
// every half of MaxIdleTimeout, whichever is smaller).
|
||||
KeepAlivePeriod time.Duration
|
||||
// DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899).
|
||||
// Packets will then be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
|
||||
// Note that if Path MTU discovery is causing issues on your system, please open a new issue
|
||||
// This allows the sending of QUIC packets that fully utilize the available MTU of the path.
|
||||
// Path MTU discovery is only available on systems that allow setting of the Don't Fragment (DF) bit.
|
||||
// If unavailable or disabled, packets will be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
|
||||
DisablePathMTUDiscovery bool
|
||||
// DisableVersionNegotiationPackets disables the sending of Version Negotiation packets.
|
||||
// This can be useful if version information is exchanged out-of-band.
|
||||
// It has no effect for a client.
|
||||
DisableVersionNegotiationPackets bool
|
||||
// Allow0RTT allows the application to decide if a 0-RTT connection attempt should be accepted.
|
||||
// Only valid for the server.
|
||||
Allow0RTT bool
|
||||
// Enable QUIC datagram support (RFC 9221).
|
||||
EnableDatagrams bool
|
||||
// Maximum size of QUIC datagram frames (RFC 9221).
|
||||
MaxDatagramFrameSize int64
|
||||
Tracer func(context.Context, logging.Perspective, ConnectionID) logging.ConnectionTracer
|
||||
Tracer func(context.Context, logging.Perspective, ConnectionID) *logging.ConnectionTracer
|
||||
}
|
||||
|
||||
type ClientHelloInfo struct {
|
||||
@@ -333,7 +333,17 @@ type ClientHelloInfo struct {
|
||||
|
||||
// ConnectionState records basic details about a QUIC connection
|
||||
type ConnectionState struct {
|
||||
TLS handshake.ConnectionState
|
||||
// TLS contains information about the TLS connection state, incl. the tls.ConnectionState.
|
||||
TLS tls.ConnectionState
|
||||
// SupportsDatagrams says if support for QUIC datagrams (RFC 9221) was negotiated.
|
||||
// This requires both nodes to support and enable the datagram extensions (via Config.EnableDatagrams).
|
||||
// If datagram support was negotiated, datagrams can be sent and received using the
|
||||
// SendDatagram and ReceiveDatagram methods on the Connection.
|
||||
SupportsDatagrams bool
|
||||
Version VersionNumber
|
||||
// Used0RTT says if 0-RTT resumption was used.
|
||||
Used0RTT bool
|
||||
// Version is the QUIC version of the QUIC connection.
|
||||
Version VersionNumber
|
||||
// GSO says if generic segmentation offload is used
|
||||
GSO bool
|
||||
}
|
||||
|
||||
2
vendor/github.com/quic-go/quic-go/internal/ackhandler/ack_eliciting.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/internal/ackhandler/ack_eliciting.go
generated
vendored
@@ -10,7 +10,7 @@ func IsFrameAckEliciting(f wire.Frame) bool {
|
||||
}
|
||||
|
||||
// HasAckElicitingFrames returns true if at least one frame is ack-eliciting.
|
||||
func HasAckElicitingFrames(fs []*Frame) bool {
|
||||
func HasAckElicitingFrames(fs []Frame) bool {
|
||||
for _, f := range fs {
|
||||
if IsFrameAckEliciting(f.Frame) {
|
||||
return true
|
||||
|
||||
5
vendor/github.com/quic-go/quic-go/internal/ackhandler/ackhandler.go
generated
vendored
5
vendor/github.com/quic-go/quic-go/internal/ackhandler/ackhandler.go
generated
vendored
@@ -14,10 +14,11 @@ func NewAckHandler(
|
||||
initialMaxDatagramSize protocol.ByteCount,
|
||||
rttStats *utils.RTTStats,
|
||||
clientAddressValidated bool,
|
||||
enableECN bool,
|
||||
pers protocol.Perspective,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
) (SentPacketHandler, ReceivedPacketHandler) {
|
||||
sph := newSentPacketHandler(initialPacketNumber, initialMaxDatagramSize, rttStats, clientAddressValidated, pers, tracer, logger)
|
||||
sph := newSentPacketHandler(initialPacketNumber, initialMaxDatagramSize, rttStats, clientAddressValidated, enableECN, pers, tracer, logger)
|
||||
return sph, newReceivedPacketHandler(sph, rttStats, logger)
|
||||
}
|
||||
|
||||
296
vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
generated
vendored
Normal file
296
vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
generated
vendored
Normal file
@@ -0,0 +1,296 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
)
|
||||
|
||||
type ecnState uint8
|
||||
|
||||
const (
|
||||
ecnStateInitial ecnState = iota
|
||||
ecnStateTesting
|
||||
ecnStateUnknown
|
||||
ecnStateCapable
|
||||
ecnStateFailed
|
||||
)
|
||||
|
||||
// must fit into an uint8, otherwise numSentTesting and numLostTesting must have a larger type
|
||||
const numECNTestingPackets = 10
|
||||
|
||||
type ecnHandler interface {
|
||||
SentPacket(protocol.PacketNumber, protocol.ECN)
|
||||
Mode() protocol.ECN
|
||||
HandleNewlyAcked(packets []*packet, ect0, ect1, ecnce int64) (congested bool)
|
||||
LostPacket(protocol.PacketNumber)
|
||||
}
|
||||
|
||||
// The ecnTracker performs ECN validation of a path.
|
||||
// Once failed, it doesn't do any re-validation of the path.
|
||||
// It is designed only work for 1-RTT packets, it doesn't handle multiple packet number spaces.
|
||||
// In order to avoid revealing any internal state to on-path observers,
|
||||
// callers should make sure to start using ECN (i.e. calling Mode) for the very first 1-RTT packet sent.
|
||||
// The validation logic implemented here strictly follows the algorithm described in RFC 9000 section 13.4.2 and A.4.
|
||||
type ecnTracker struct {
|
||||
state ecnState
|
||||
numSentTesting, numLostTesting uint8
|
||||
|
||||
firstTestingPacket protocol.PacketNumber
|
||||
lastTestingPacket protocol.PacketNumber
|
||||
firstCapablePacket protocol.PacketNumber
|
||||
|
||||
numSentECT0, numSentECT1 int64
|
||||
numAckedECT0, numAckedECT1, numAckedECNCE int64
|
||||
|
||||
tracer *logging.ConnectionTracer
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
var _ ecnHandler = &ecnTracker{}
|
||||
|
||||
func newECNTracker(logger utils.Logger, tracer *logging.ConnectionTracer) *ecnTracker {
|
||||
return &ecnTracker{
|
||||
firstTestingPacket: protocol.InvalidPacketNumber,
|
||||
lastTestingPacket: protocol.InvalidPacketNumber,
|
||||
firstCapablePacket: protocol.InvalidPacketNumber,
|
||||
state: ecnStateInitial,
|
||||
logger: logger,
|
||||
tracer: tracer,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ecnTracker) SentPacket(pn protocol.PacketNumber, ecn protocol.ECN) {
|
||||
//nolint:exhaustive // These are the only ones we need to take care of.
|
||||
switch ecn {
|
||||
case protocol.ECNNon:
|
||||
return
|
||||
case protocol.ECT0:
|
||||
e.numSentECT0++
|
||||
case protocol.ECT1:
|
||||
e.numSentECT1++
|
||||
case protocol.ECNUnsupported:
|
||||
if e.state != ecnStateFailed {
|
||||
panic("didn't expect ECN to be unsupported")
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("sent packet with unexpected ECN marking: %s", ecn))
|
||||
}
|
||||
|
||||
if e.state == ecnStateCapable && e.firstCapablePacket == protocol.InvalidPacketNumber {
|
||||
e.firstCapablePacket = pn
|
||||
}
|
||||
|
||||
if e.state != ecnStateTesting {
|
||||
return
|
||||
}
|
||||
|
||||
e.numSentTesting++
|
||||
if e.firstTestingPacket == protocol.InvalidPacketNumber {
|
||||
e.firstTestingPacket = pn
|
||||
}
|
||||
if e.numSentECT0+e.numSentECT1 >= numECNTestingPackets {
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateUnknown, logging.ECNTriggerNoTrigger)
|
||||
}
|
||||
e.state = ecnStateUnknown
|
||||
e.lastTestingPacket = pn
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ecnTracker) Mode() protocol.ECN {
|
||||
switch e.state {
|
||||
case ecnStateInitial:
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateTesting, logging.ECNTriggerNoTrigger)
|
||||
}
|
||||
e.state = ecnStateTesting
|
||||
return e.Mode()
|
||||
case ecnStateTesting, ecnStateCapable:
|
||||
return protocol.ECT0
|
||||
case ecnStateUnknown, ecnStateFailed:
|
||||
return protocol.ECNNon
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown ECN state: %d", e.state))
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ecnTracker) LostPacket(pn protocol.PacketNumber) {
|
||||
if e.state != ecnStateTesting && e.state != ecnStateUnknown {
|
||||
return
|
||||
}
|
||||
if !e.isTestingPacket(pn) {
|
||||
return
|
||||
}
|
||||
e.numLostTesting++
|
||||
// Only proceed if we have sent all 10 testing packets.
|
||||
if e.state != ecnStateUnknown {
|
||||
return
|
||||
}
|
||||
if e.numLostTesting >= e.numSentTesting {
|
||||
e.logger.Debugf("Disabling ECN. All testing packets were lost.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedLostAllTestingPackets)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return
|
||||
}
|
||||
// Path validation also fails if some testing packets are lost, and all other testing packets where CE-marked
|
||||
e.failIfMangled()
|
||||
}
|
||||
|
||||
// HandleNewlyAcked handles the ECN counts on an ACK frame.
|
||||
// It must only be called for ACK frames that increase the largest acknowledged packet number,
|
||||
// see section 13.4.2.1 of RFC 9000.
|
||||
func (e *ecnTracker) HandleNewlyAcked(packets []*packet, ect0, ect1, ecnce int64) (congested bool) {
|
||||
if e.state == ecnStateFailed {
|
||||
return false
|
||||
}
|
||||
|
||||
// ECN validation can fail if the received total count for either ECT(0) or ECT(1) exceeds
|
||||
// the total number of packets sent with each corresponding ECT codepoint.
|
||||
if ect0 > e.numSentECT0 || ect1 > e.numSentECT1 {
|
||||
e.logger.Debugf("Disabling ECN. Received more ECT(0) / ECT(1) acknowledgements than packets sent.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedMoreECNCountsThanSent)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
|
||||
// Count ECT0 and ECT1 marks that we used when sending the packets that are now being acknowledged.
|
||||
var ackedECT0, ackedECT1 int64
|
||||
for _, p := range packets {
|
||||
//nolint:exhaustive // We only ever send ECT(0) and ECT(1).
|
||||
switch e.ecnMarking(p.PacketNumber) {
|
||||
case protocol.ECT0:
|
||||
ackedECT0++
|
||||
case protocol.ECT1:
|
||||
ackedECT1++
|
||||
}
|
||||
}
|
||||
|
||||
// If an ACK frame newly acknowledges a packet that the endpoint sent with either the ECT(0) or ECT(1)
|
||||
// codepoint set, ECN validation fails if the corresponding ECN counts are not present in the ACK frame.
|
||||
// This check detects:
|
||||
// * paths that bleach all ECN marks, and
|
||||
// * peers that don't report any ECN counts
|
||||
if (ackedECT0 > 0 || ackedECT1 > 0) && ect0 == 0 && ect1 == 0 && ecnce == 0 {
|
||||
e.logger.Debugf("Disabling ECN. ECN-marked packet acknowledged, but no ECN counts on ACK frame.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedNoECNCounts)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
|
||||
// Determine the increase in ECT0, ECT1 and ECNCE marks
|
||||
newECT0 := ect0 - e.numAckedECT0
|
||||
newECT1 := ect1 - e.numAckedECT1
|
||||
newECNCE := ecnce - e.numAckedECNCE
|
||||
|
||||
// We're only processing ACKs that increase the Largest Acked.
|
||||
// Therefore, the ECN counters should only ever increase.
|
||||
// Any decrease means that the peer's counting logic is broken.
|
||||
if newECT0 < 0 || newECT1 < 0 || newECNCE < 0 {
|
||||
e.logger.Debugf("Disabling ECN. ECN counts decreased unexpectedly.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedDecreasedECNCounts)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
|
||||
// ECN validation also fails if the sum of the increase in ECT(0) and ECN-CE counts is less than the number
|
||||
// of newly acknowledged packets that were originally sent with an ECT(0) marking.
|
||||
// This could be the result of (partial) bleaching.
|
||||
if newECT0+newECNCE < ackedECT0 {
|
||||
e.logger.Debugf("Disabling ECN. Received less ECT(0) + ECN-CE than packets sent with ECT(0).")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedTooFewECNCounts)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
// Similarly, ECN validation fails if the sum of the increases to ECT(1) and ECN-CE counts is less than
|
||||
// the number of newly acknowledged packets sent with an ECT(1) marking.
|
||||
if newECT1+newECNCE < ackedECT1 {
|
||||
e.logger.Debugf("Disabling ECN. Received less ECT(1) + ECN-CE than packets sent with ECT(1).")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedTooFewECNCounts)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
return false
|
||||
}
|
||||
|
||||
// update our counters
|
||||
e.numAckedECT0 = ect0
|
||||
e.numAckedECT1 = ect1
|
||||
e.numAckedECNCE = ecnce
|
||||
|
||||
// Detect mangling (a path remarking all ECN-marked testing packets as CE),
|
||||
// once all 10 testing packets have been sent out.
|
||||
if e.state == ecnStateUnknown {
|
||||
e.failIfMangled()
|
||||
if e.state == ecnStateFailed {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if e.state == ecnStateTesting || e.state == ecnStateUnknown {
|
||||
var ackedTestingPacket bool
|
||||
for _, p := range packets {
|
||||
if e.isTestingPacket(p.PacketNumber) {
|
||||
ackedTestingPacket = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// This check won't succeed if the path is mangling ECN-marks (i.e. rewrites all ECN-marked packets to CE).
|
||||
if ackedTestingPacket && (newECT0 > 0 || newECT1 > 0) {
|
||||
e.logger.Debugf("ECN capability confirmed.")
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateCapable, logging.ECNTriggerNoTrigger)
|
||||
}
|
||||
e.state = ecnStateCapable
|
||||
}
|
||||
}
|
||||
|
||||
// Don't trust CE marks before having confirmed ECN capability of the path.
|
||||
// Otherwise, mangling would be misinterpreted as actual congestion.
|
||||
return e.state == ecnStateCapable && newECNCE > 0
|
||||
}
|
||||
|
||||
// failIfMangled fails ECN validation if all testing packets are lost or CE-marked.
|
||||
func (e *ecnTracker) failIfMangled() {
|
||||
numAckedECNCE := e.numAckedECNCE + int64(e.numLostTesting)
|
||||
if e.numSentECT0+e.numSentECT1 > numAckedECNCE {
|
||||
return
|
||||
}
|
||||
if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
|
||||
e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedManglingDetected)
|
||||
}
|
||||
e.state = ecnStateFailed
|
||||
}
|
||||
|
||||
func (e *ecnTracker) ecnMarking(pn protocol.PacketNumber) protocol.ECN {
|
||||
if pn < e.firstTestingPacket || e.firstTestingPacket == protocol.InvalidPacketNumber {
|
||||
return protocol.ECNNon
|
||||
}
|
||||
if pn < e.lastTestingPacket || e.lastTestingPacket == protocol.InvalidPacketNumber {
|
||||
return protocol.ECT0
|
||||
}
|
||||
if pn < e.firstCapablePacket || e.firstCapablePacket == protocol.InvalidPacketNumber {
|
||||
return protocol.ECNNon
|
||||
}
|
||||
// We don't need to deal with the case when ECN validation fails,
|
||||
// since we're ignoring any ECN counts reported in ACK frames in that case.
|
||||
return protocol.ECT0
|
||||
}
|
||||
|
||||
func (e *ecnTracker) isTestingPacket(pn protocol.PacketNumber) bool {
|
||||
if e.firstTestingPacket == protocol.InvalidPacketNumber {
|
||||
return false
|
||||
}
|
||||
return pn >= e.firstTestingPacket && (pn <= e.lastTestingPacket || e.lastTestingPacket == protocol.InvalidPacketNumber)
|
||||
}
|
||||
30
vendor/github.com/quic-go/quic-go/internal/ackhandler/frame.go
generated
vendored
30
vendor/github.com/quic-go/quic-go/internal/ackhandler/frame.go
generated
vendored
@@ -1,29 +1,21 @@
|
||||
package ackhandler
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
// FrameHandler handles the acknowledgement and the loss of a frame.
|
||||
type FrameHandler interface {
|
||||
OnAcked(wire.Frame)
|
||||
OnLost(wire.Frame)
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
wire.Frame // nil if the frame has already been acknowledged in another packet
|
||||
OnLost func(wire.Frame)
|
||||
OnAcked func(wire.Frame)
|
||||
Frame wire.Frame // nil if the frame has already been acknowledged in another packet
|
||||
Handler FrameHandler
|
||||
}
|
||||
|
||||
var framePool = sync.Pool{New: func() any { return &Frame{} }}
|
||||
|
||||
func GetFrame() *Frame {
|
||||
f := framePool.Get().(*Frame)
|
||||
f.OnLost = nil
|
||||
f.OnAcked = nil
|
||||
return f
|
||||
}
|
||||
|
||||
func putFrame(f *Frame) {
|
||||
f.Frame = nil
|
||||
f.OnLost = nil
|
||||
f.OnAcked = nil
|
||||
framePool.Put(f)
|
||||
type StreamFrame struct {
|
||||
Frame *wire.StreamFrame
|
||||
Handler FrameHandler
|
||||
}
|
||||
|
||||
15
vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
generated
vendored
15
vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
generated
vendored
@@ -10,25 +10,26 @@ import (
|
||||
// SentPacketHandler handles ACKs received for outgoing packets
|
||||
type SentPacketHandler interface {
|
||||
// SentPacket may modify the packet
|
||||
SentPacket(packet *Packet)
|
||||
ReceivedAck(ackFrame *wire.AckFrame, encLevel protocol.EncryptionLevel, recvTime time.Time) (bool /* 1-RTT packet acked */, error)
|
||||
SentPacket(t time.Time, pn, largestAcked protocol.PacketNumber, streamFrames []StreamFrame, frames []Frame, encLevel protocol.EncryptionLevel, ecn protocol.ECN, size protocol.ByteCount, isPathMTUProbePacket bool)
|
||||
// ReceivedAck processes an ACK frame.
|
||||
// It does not store a copy of the frame.
|
||||
ReceivedAck(f *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) (bool /* 1-RTT packet acked */, error)
|
||||
ReceivedBytes(protocol.ByteCount)
|
||||
DropPackets(protocol.EncryptionLevel)
|
||||
ResetForRetry() error
|
||||
ResetForRetry(rcvTime time.Time) error
|
||||
SetHandshakeConfirmed()
|
||||
|
||||
// The SendMode determines if and what kind of packets can be sent.
|
||||
SendMode() SendMode
|
||||
SendMode(now time.Time) SendMode
|
||||
// TimeUntilSend is the time when the next packet should be sent.
|
||||
// It is used for pacing packets.
|
||||
TimeUntilSend() time.Time
|
||||
// HasPacingBudget says if the pacer allows sending of a (full size) packet at this moment.
|
||||
HasPacingBudget() bool
|
||||
SetMaxDatagramSize(count protocol.ByteCount)
|
||||
|
||||
// only to be called once the handshake is complete
|
||||
QueueProbePacket(protocol.EncryptionLevel) bool /* was a packet queued */
|
||||
|
||||
ECNMode(isShortHeaderPacket bool) protocol.ECN // isShortHeaderPacket should only be true for non-coalesced 1-RTT packets
|
||||
PeekPacketNumber(protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen)
|
||||
PopPacketNumber(protocol.EncryptionLevel) protocol.PacketNumber
|
||||
|
||||
@@ -44,7 +45,7 @@ type sentPacketTracker interface {
|
||||
// ReceivedPacketHandler handles ACKs needed to send for incoming packets
|
||||
type ReceivedPacketHandler interface {
|
||||
IsPotentiallyDuplicate(protocol.PacketNumber, protocol.EncryptionLevel) bool
|
||||
ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, encLevel protocol.EncryptionLevel, rcvTime time.Time, shouldInstigateAck bool) error
|
||||
ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, encLevel protocol.EncryptionLevel, rcvTime time.Time, ackEliciting bool) error
|
||||
DropPackets(protocol.EncryptionLevel)
|
||||
|
||||
GetAlarmTimeout() time.Time
|
||||
|
||||
5
vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
generated
vendored
5
vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
generated
vendored
@@ -2,5 +2,8 @@
|
||||
|
||||
package ackhandler
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/quic-go/quic-go/internal/ackhandler SentPacketTracker"
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/quic-go/quic-go/internal/ackhandler SentPacketTracker"
|
||||
type SentPacketTracker = sentPacketTracker
|
||||
|
||||
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_ecn_handler_test.go github.com/quic-go/quic-go/internal/ackhandler ECNHandler"
|
||||
type ECNHandler = ecnHandler
|
||||
|
||||
22
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
generated
vendored
22
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
generated
vendored
@@ -8,13 +8,14 @@ import (
|
||||
)
|
||||
|
||||
// A Packet is a packet
|
||||
type Packet struct {
|
||||
type packet struct {
|
||||
SendTime time.Time
|
||||
PacketNumber protocol.PacketNumber
|
||||
Frames []*Frame
|
||||
StreamFrames []StreamFrame
|
||||
Frames []Frame
|
||||
LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
|
||||
Length protocol.ByteCount
|
||||
EncryptionLevel protocol.EncryptionLevel
|
||||
SendTime time.Time
|
||||
|
||||
IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.
|
||||
|
||||
@@ -23,15 +24,16 @@ type Packet struct {
|
||||
skippedPacket bool
|
||||
}
|
||||
|
||||
func (p *Packet) outstanding() bool {
|
||||
func (p *packet) outstanding() bool {
|
||||
return !p.declaredLost && !p.skippedPacket && !p.IsPathMTUProbePacket
|
||||
}
|
||||
|
||||
var packetPool = sync.Pool{New: func() any { return &Packet{} }}
|
||||
var packetPool = sync.Pool{New: func() any { return &packet{} }}
|
||||
|
||||
func GetPacket() *Packet {
|
||||
p := packetPool.Get().(*Packet)
|
||||
func getPacket() *packet {
|
||||
p := packetPool.Get().(*packet)
|
||||
p.PacketNumber = 0
|
||||
p.StreamFrames = nil
|
||||
p.Frames = nil
|
||||
p.LargestAcked = 0
|
||||
p.Length = 0
|
||||
@@ -46,10 +48,8 @@ func GetPacket() *Packet {
|
||||
|
||||
// We currently only return Packets back into the pool when they're acknowledged (not when they're lost).
|
||||
// This simplifies the code, and gives the vast majority of the performance benefit we can gain from using the pool.
|
||||
func putPacket(p *Packet) {
|
||||
for _, f := range p.Frames {
|
||||
putFrame(f)
|
||||
}
|
||||
func putPacket(p *packet) {
|
||||
p.Frames = nil
|
||||
p.StreamFrames = nil
|
||||
packetPool.Put(p)
|
||||
}
|
||||
|
||||
24
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet_number_generator.go
generated
vendored
24
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet_number_generator.go
generated
vendored
@@ -7,7 +7,10 @@ import (
|
||||
|
||||
type packetNumberGenerator interface {
|
||||
Peek() protocol.PacketNumber
|
||||
Pop() protocol.PacketNumber
|
||||
// Pop pops the packet number.
|
||||
// It reports if the packet number (before the one just popped) was skipped.
|
||||
// It never skips more than one packet number in a row.
|
||||
Pop() (skipped bool, _ protocol.PacketNumber)
|
||||
}
|
||||
|
||||
type sequentialPacketNumberGenerator struct {
|
||||
@@ -24,10 +27,10 @@ func (p *sequentialPacketNumberGenerator) Peek() protocol.PacketNumber {
|
||||
return p.next
|
||||
}
|
||||
|
||||
func (p *sequentialPacketNumberGenerator) Pop() protocol.PacketNumber {
|
||||
func (p *sequentialPacketNumberGenerator) Pop() (bool, protocol.PacketNumber) {
|
||||
next := p.next
|
||||
p.next++
|
||||
return next
|
||||
return false, next
|
||||
}
|
||||
|
||||
// The skippingPacketNumberGenerator generates the packet number for the next packet
|
||||
@@ -56,21 +59,26 @@ func newSkippingPacketNumberGenerator(initial, initialPeriod, maxPeriod protocol
|
||||
}
|
||||
|
||||
func (p *skippingPacketNumberGenerator) Peek() protocol.PacketNumber {
|
||||
if p.next == p.nextToSkip {
|
||||
return p.next + 1
|
||||
}
|
||||
return p.next
|
||||
}
|
||||
|
||||
func (p *skippingPacketNumberGenerator) Pop() protocol.PacketNumber {
|
||||
func (p *skippingPacketNumberGenerator) Pop() (bool, protocol.PacketNumber) {
|
||||
next := p.next
|
||||
p.next++ // generate a new packet number for the next packet
|
||||
if p.next == p.nextToSkip {
|
||||
p.next++
|
||||
next++
|
||||
p.next += 2
|
||||
p.generateNewSkip()
|
||||
return true, next
|
||||
}
|
||||
return next
|
||||
p.next++ // generate a new packet number for the next packet
|
||||
return false, next
|
||||
}
|
||||
|
||||
func (p *skippingPacketNumberGenerator) generateNewSkip() {
|
||||
// make sure that there are never two consecutive packet numbers that are skipped
|
||||
p.nextToSkip = p.next + 2 + protocol.PacketNumber(p.rng.Int31n(int32(2*p.period)))
|
||||
p.nextToSkip = p.next + 3 + protocol.PacketNumber(p.rng.Int31n(int32(2*p.period)))
|
||||
p.period = utils.Min(2*p.period, p.maxPeriod)
|
||||
}
|
||||
|
||||
15
vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
generated
vendored
15
vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
generated
vendored
@@ -40,24 +40,29 @@ func (h *receivedPacketHandler) ReceivedPacket(
|
||||
ecn protocol.ECN,
|
||||
encLevel protocol.EncryptionLevel,
|
||||
rcvTime time.Time,
|
||||
shouldInstigateAck bool,
|
||||
ackEliciting bool,
|
||||
) error {
|
||||
h.sentPackets.ReceivedPacket(encLevel)
|
||||
switch encLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
return h.initialPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
return h.initialPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting)
|
||||
case protocol.EncryptionHandshake:
|
||||
return h.handshakePackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
// The Handshake packet number space might already have been dropped as a result
|
||||
// of processing the CRYPTO frame that was contained in this packet.
|
||||
if h.handshakePackets == nil {
|
||||
return nil
|
||||
}
|
||||
return h.handshakePackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting)
|
||||
case protocol.Encryption0RTT:
|
||||
if h.lowest1RTTPacket != protocol.InvalidPacketNumber && pn > h.lowest1RTTPacket {
|
||||
return fmt.Errorf("received packet number %d on a 0-RTT packet after receiving %d on a 1-RTT packet", pn, h.lowest1RTTPacket)
|
||||
}
|
||||
return h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck)
|
||||
return h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting)
|
||||
case protocol.Encryption1RTT:
|
||||
if h.lowest1RTTPacket == protocol.InvalidPacketNumber || pn < h.lowest1RTTPacket {
|
||||
h.lowest1RTTPacket = pn
|
||||
}
|
||||
if err := h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, shouldInstigateAck); err != nil {
|
||||
if err := h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting); err != nil {
|
||||
return err
|
||||
}
|
||||
h.appDataPackets.IgnoreBelow(h.sentPackets.GetLowestPacketNotConfirmedAcked())
|
||||
|
||||
64
vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
generated
vendored
64
vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
generated
vendored
@@ -13,10 +13,10 @@ import (
|
||||
const packetsBeforeAck = 2
|
||||
|
||||
type receivedPacketTracker struct {
|
||||
largestObserved protocol.PacketNumber
|
||||
ignoreBelow protocol.PacketNumber
|
||||
largestObservedReceivedTime time.Time
|
||||
ect0, ect1, ecnce uint64
|
||||
largestObserved protocol.PacketNumber
|
||||
ignoreBelow protocol.PacketNumber
|
||||
largestObservedRcvdTime time.Time
|
||||
ect0, ect1, ecnce uint64
|
||||
|
||||
packetHistory *receivedPacketHistory
|
||||
|
||||
@@ -45,25 +45,23 @@ func newReceivedPacketTracker(
|
||||
}
|
||||
}
|
||||
|
||||
func (h *receivedPacketTracker) ReceivedPacket(packetNumber protocol.PacketNumber, ecn protocol.ECN, rcvTime time.Time, shouldInstigateAck bool) error {
|
||||
if isNew := h.packetHistory.ReceivedPacket(packetNumber); !isNew {
|
||||
return fmt.Errorf("recevedPacketTracker BUG: ReceivedPacket called for old / duplicate packet %d", packetNumber)
|
||||
func (h *receivedPacketTracker) ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, rcvTime time.Time, ackEliciting bool) error {
|
||||
if isNew := h.packetHistory.ReceivedPacket(pn); !isNew {
|
||||
return fmt.Errorf("recevedPacketTracker BUG: ReceivedPacket called for old / duplicate packet %d", pn)
|
||||
}
|
||||
|
||||
isMissing := h.isMissing(packetNumber)
|
||||
if packetNumber >= h.largestObserved {
|
||||
h.largestObserved = packetNumber
|
||||
h.largestObservedReceivedTime = rcvTime
|
||||
isMissing := h.isMissing(pn)
|
||||
if pn >= h.largestObserved {
|
||||
h.largestObserved = pn
|
||||
h.largestObservedRcvdTime = rcvTime
|
||||
}
|
||||
|
||||
if shouldInstigateAck {
|
||||
if ackEliciting {
|
||||
h.hasNewAck = true
|
||||
h.maybeQueueACK(pn, rcvTime, ecn, isMissing)
|
||||
}
|
||||
if shouldInstigateAck {
|
||||
h.maybeQueueAck(packetNumber, rcvTime, isMissing)
|
||||
}
|
||||
//nolint:exhaustive // Only need to count ECT(0), ECT(1) and ECN-CE.
|
||||
switch ecn {
|
||||
case protocol.ECNNon:
|
||||
case protocol.ECT0:
|
||||
h.ect0++
|
||||
case protocol.ECT1:
|
||||
@@ -76,14 +74,14 @@ func (h *receivedPacketTracker) ReceivedPacket(packetNumber protocol.PacketNumbe
|
||||
|
||||
// IgnoreBelow sets a lower limit for acknowledging packets.
|
||||
// Packets with packet numbers smaller than p will not be acked.
|
||||
func (h *receivedPacketTracker) IgnoreBelow(p protocol.PacketNumber) {
|
||||
if p <= h.ignoreBelow {
|
||||
func (h *receivedPacketTracker) IgnoreBelow(pn protocol.PacketNumber) {
|
||||
if pn <= h.ignoreBelow {
|
||||
return
|
||||
}
|
||||
h.ignoreBelow = p
|
||||
h.packetHistory.DeleteBelow(p)
|
||||
h.ignoreBelow = pn
|
||||
h.packetHistory.DeleteBelow(pn)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tIgnoring all packets below %d.", p)
|
||||
h.logger.Debugf("\tIgnoring all packets below %d.", pn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +101,8 @@ func (h *receivedPacketTracker) hasNewMissingPackets() bool {
|
||||
return highestRange.Smallest > h.lastAck.LargestAcked()+1 && highestRange.Len() == 1
|
||||
}
|
||||
|
||||
// maybeQueueAck queues an ACK, if necessary.
|
||||
func (h *receivedPacketTracker) maybeQueueAck(pn protocol.PacketNumber, rcvTime time.Time, wasMissing bool) {
|
||||
// maybeQueueACK queues an ACK, if necessary.
|
||||
func (h *receivedPacketTracker) maybeQueueACK(pn protocol.PacketNumber, rcvTime time.Time, ecn protocol.ECN, wasMissing bool) {
|
||||
// always acknowledge the first packet
|
||||
if h.lastAck == nil {
|
||||
if !h.ackQueued {
|
||||
@@ -143,12 +141,18 @@ func (h *receivedPacketTracker) maybeQueueAck(pn protocol.PacketNumber, rcvTime
|
||||
h.ackAlarm = rcvTime.Add(h.maxAckDelay)
|
||||
}
|
||||
|
||||
// Queue an ACK if there are new missing packets to report.
|
||||
// queue an ACK if there are new missing packets to report
|
||||
if h.hasNewMissingPackets() {
|
||||
h.logger.Debugf("\tQueuing ACK because there's a new missing packet to report.")
|
||||
h.ackQueued = true
|
||||
}
|
||||
|
||||
// queue an ACK if the packet was ECN-CE marked
|
||||
if ecn == protocol.ECNCE {
|
||||
h.logger.Debugf("\tQueuing ACK because the packet was ECN-CE marked.")
|
||||
h.ackQueued = true
|
||||
}
|
||||
|
||||
if h.ackQueued {
|
||||
// cancel the ack alarm
|
||||
h.ackAlarm = time.Time{}
|
||||
@@ -169,16 +173,18 @@ func (h *receivedPacketTracker) GetAckFrame(onlyIfQueued bool) *wire.AckFrame {
|
||||
}
|
||||
}
|
||||
|
||||
ack := wire.GetAckFrame()
|
||||
ack.DelayTime = utils.Max(0, now.Sub(h.largestObservedReceivedTime))
|
||||
// This function always returns the same ACK frame struct, filled with the most recent values.
|
||||
ack := h.lastAck
|
||||
if ack == nil {
|
||||
ack = &wire.AckFrame{}
|
||||
}
|
||||
ack.Reset()
|
||||
ack.DelayTime = utils.Max(0, now.Sub(h.largestObservedRcvdTime))
|
||||
ack.ECT0 = h.ect0
|
||||
ack.ECT1 = h.ect1
|
||||
ack.ECNCE = h.ecnce
|
||||
ack.AckRanges = h.packetHistory.AppendAckRanges(ack.AckRanges)
|
||||
|
||||
if h.lastAck != nil {
|
||||
wire.PutAckFrame(h.lastAck)
|
||||
}
|
||||
h.lastAck = ack
|
||||
h.ackAlarm = time.Time{}
|
||||
h.ackQueued = false
|
||||
|
||||
6
vendor/github.com/quic-go/quic-go/internal/ackhandler/send_mode.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/ackhandler/send_mode.go
generated
vendored
@@ -16,6 +16,10 @@ const (
|
||||
SendPTOHandshake
|
||||
// SendPTOAppData means that an Application data probe packet should be sent
|
||||
SendPTOAppData
|
||||
// SendPacingLimited means that the pacer doesn't allow sending of a packet right now,
|
||||
// but will do in a little while.
|
||||
// The timestamp when sending is allowed again can be obtained via the SentPacketHandler.TimeUntilSend.
|
||||
SendPacingLimited
|
||||
// SendAny means that any packet should be sent
|
||||
SendAny
|
||||
)
|
||||
@@ -34,6 +38,8 @@ func (s SendMode) String() string {
|
||||
return "pto (Application Data)"
|
||||
case SendAny:
|
||||
return "any"
|
||||
case SendPacingLimited:
|
||||
return "pacing limited"
|
||||
default:
|
||||
return fmt.Sprintf("invalid send mode: %d", s)
|
||||
}
|
||||
|
||||
329
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go
generated
vendored
329
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go
generated
vendored
@@ -38,7 +38,7 @@ type packetNumberSpace struct {
|
||||
largestSent protocol.PacketNumber
|
||||
}
|
||||
|
||||
func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool, rttStats *utils.RTTStats) *packetNumberSpace {
|
||||
func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool) *packetNumberSpace {
|
||||
var pns packetNumberGenerator
|
||||
if skipPNs {
|
||||
pns = newSkippingPacketNumberGenerator(initialPN, protocol.SkipPacketInitialPeriod, protocol.SkipPacketMaxPeriod)
|
||||
@@ -46,7 +46,7 @@ func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool, rttStat
|
||||
pns = newSequentialPacketNumberGenerator(initialPN)
|
||||
}
|
||||
return &packetNumberSpace{
|
||||
history: newSentPacketHistory(rttStats),
|
||||
history: newSentPacketHistory(),
|
||||
pns: pns,
|
||||
largestSent: protocol.InvalidPacketNumber,
|
||||
largestAcked: protocol.InvalidPacketNumber,
|
||||
@@ -75,7 +75,7 @@ type sentPacketHandler struct {
|
||||
// Only applies to the application-data packet number space.
|
||||
lowestNotConfirmedAcked protocol.PacketNumber
|
||||
|
||||
ackedPackets []*Packet // to avoid allocations in detectAndRemoveAckedPackets
|
||||
ackedPackets []*packet // to avoid allocations in detectAndRemoveAckedPackets
|
||||
|
||||
bytesInFlight protocol.ByteCount
|
||||
|
||||
@@ -92,9 +92,12 @@ type sentPacketHandler struct {
|
||||
// The alarm timeout
|
||||
alarm time.Time
|
||||
|
||||
enableECN bool
|
||||
ecnTracker ecnHandler
|
||||
|
||||
perspective protocol.Perspective
|
||||
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
@@ -110,8 +113,9 @@ func newSentPacketHandler(
|
||||
initialMaxDatagramSize protocol.ByteCount,
|
||||
rttStats *utils.RTTStats,
|
||||
clientAddressValidated bool,
|
||||
enableECN bool,
|
||||
pers protocol.Perspective,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
) *sentPacketHandler {
|
||||
congestion := congestion.NewCubicSender(
|
||||
@@ -122,31 +126,26 @@ func newSentPacketHandler(
|
||||
tracer,
|
||||
)
|
||||
|
||||
return &sentPacketHandler{
|
||||
h := &sentPacketHandler{
|
||||
peerCompletedAddressValidation: pers == protocol.PerspectiveServer,
|
||||
peerAddressValidated: pers == protocol.PerspectiveClient || clientAddressValidated,
|
||||
initialPackets: newPacketNumberSpace(initialPN, false, rttStats),
|
||||
handshakePackets: newPacketNumberSpace(0, false, rttStats),
|
||||
appDataPackets: newPacketNumberSpace(0, true, rttStats),
|
||||
initialPackets: newPacketNumberSpace(initialPN, false),
|
||||
handshakePackets: newPacketNumberSpace(0, false),
|
||||
appDataPackets: newPacketNumberSpace(0, true),
|
||||
rttStats: rttStats,
|
||||
congestion: congestion,
|
||||
perspective: pers,
|
||||
tracer: tracer,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
|
||||
if h.perspective == protocol.PerspectiveClient && encLevel == protocol.EncryptionInitial {
|
||||
// This function is called when the crypto setup seals a Handshake packet.
|
||||
// If this Handshake packet is coalesced behind an Initial packet, we would drop the Initial packet number space
|
||||
// before SentPacket() was called for that Initial packet.
|
||||
return
|
||||
if enableECN {
|
||||
h.enableECN = true
|
||||
h.ecnTracker = newECNTracker(logger, tracer)
|
||||
}
|
||||
h.dropPackets(encLevel)
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) removeFromBytesInFlight(p *Packet) {
|
||||
func (h *sentPacketHandler) removeFromBytesInFlight(p *packet) {
|
||||
if p.includedInBytesInFlight {
|
||||
if p.Length > h.bytesInFlight {
|
||||
panic("negative bytes_in_flight")
|
||||
@@ -156,7 +155,7 @@ func (h *sentPacketHandler) removeFromBytesInFlight(p *Packet) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
|
||||
func (h *sentPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
|
||||
// The server won't await address validation after the handshake is confirmed.
|
||||
// This applies even if we didn't receive an ACK for a Handshake packet.
|
||||
if h.perspective == protocol.PerspectiveClient && encLevel == protocol.EncryptionHandshake {
|
||||
@@ -165,7 +164,11 @@ func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
|
||||
// remove outstanding packets from bytes_in_flight
|
||||
if encLevel == protocol.EncryptionInitial || encLevel == protocol.EncryptionHandshake {
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
pnSpace.history.Iterate(func(p *Packet) (bool, error) {
|
||||
// We might already have dropped this packet number space.
|
||||
if pnSpace == nil {
|
||||
return
|
||||
}
|
||||
pnSpace.history.Iterate(func(p *packet) (bool, error) {
|
||||
h.removeFromBytesInFlight(p)
|
||||
return true, nil
|
||||
})
|
||||
@@ -182,8 +185,8 @@ func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
|
||||
// and not when the client drops 0-RTT keys when the handshake completes.
|
||||
// When 0-RTT is rejected, all application data sent so far becomes invalid.
|
||||
// Delete the packets from the history and remove them from bytes_in_flight.
|
||||
h.appDataPackets.history.Iterate(func(p *Packet) (bool, error) {
|
||||
if p.EncryptionLevel != protocol.Encryption0RTT {
|
||||
h.appDataPackets.history.Iterate(func(p *packet) (bool, error) {
|
||||
if p.EncryptionLevel != protocol.Encryption0RTT && !p.skippedPacket {
|
||||
return false, nil
|
||||
}
|
||||
h.removeFromBytesInFlight(p)
|
||||
@@ -193,7 +196,7 @@ func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
|
||||
default:
|
||||
panic(fmt.Sprintf("Cannot drop keys for encryption level %s", encLevel))
|
||||
}
|
||||
if h.tracer != nil && h.ptoCount != 0 {
|
||||
if h.tracer != nil && h.tracer.UpdatedPTOCount != nil && h.ptoCount != 0 {
|
||||
h.tracer.UpdatedPTOCount(0)
|
||||
}
|
||||
h.ptoCount = 0
|
||||
@@ -228,26 +231,65 @@ func (h *sentPacketHandler) packetsInFlight() int {
|
||||
return packetsInFlight
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SentPacket(p *Packet) {
|
||||
h.bytesSent += p.Length
|
||||
// For the client, drop the Initial packet number space when the first Handshake packet is sent.
|
||||
if h.perspective == protocol.PerspectiveClient && p.EncryptionLevel == protocol.EncryptionHandshake && h.initialPackets != nil {
|
||||
h.dropPackets(protocol.EncryptionInitial)
|
||||
func (h *sentPacketHandler) SentPacket(
|
||||
t time.Time,
|
||||
pn, largestAcked protocol.PacketNumber,
|
||||
streamFrames []StreamFrame,
|
||||
frames []Frame,
|
||||
encLevel protocol.EncryptionLevel,
|
||||
ecn protocol.ECN,
|
||||
size protocol.ByteCount,
|
||||
isPathMTUProbePacket bool,
|
||||
) {
|
||||
h.bytesSent += size
|
||||
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
if h.logger.Debug() && pnSpace.history.HasOutstandingPackets() {
|
||||
for p := utils.Max(0, pnSpace.largestSent+1); p < pn; p++ {
|
||||
h.logger.Debugf("Skipping packet number %d", p)
|
||||
}
|
||||
}
|
||||
isAckEliciting := h.sentPacketImpl(p)
|
||||
|
||||
pnSpace.largestSent = pn
|
||||
isAckEliciting := len(streamFrames) > 0 || len(frames) > 0
|
||||
|
||||
if isAckEliciting {
|
||||
h.getPacketNumberSpace(p.EncryptionLevel).history.SentAckElicitingPacket(p)
|
||||
} else {
|
||||
h.getPacketNumberSpace(p.EncryptionLevel).history.SentNonAckElicitingPacket(p.PacketNumber, p.EncryptionLevel, p.SendTime)
|
||||
putPacket(p)
|
||||
p = nil //nolint:ineffassign // This is just to be on the safe side.
|
||||
pnSpace.lastAckElicitingPacketTime = t
|
||||
h.bytesInFlight += size
|
||||
if h.numProbesToSend > 0 {
|
||||
h.numProbesToSend--
|
||||
}
|
||||
}
|
||||
if h.tracer != nil && isAckEliciting {
|
||||
h.congestion.OnPacketSent(t, h.bytesInFlight, pn, size, isAckEliciting)
|
||||
|
||||
if encLevel == protocol.Encryption1RTT && h.ecnTracker != nil {
|
||||
h.ecnTracker.SentPacket(pn, ecn)
|
||||
}
|
||||
|
||||
if !isAckEliciting {
|
||||
pnSpace.history.SentNonAckElicitingPacket(pn)
|
||||
if !h.peerCompletedAddressValidation {
|
||||
h.setLossDetectionTimer()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
p := getPacket()
|
||||
p.SendTime = t
|
||||
p.PacketNumber = pn
|
||||
p.EncryptionLevel = encLevel
|
||||
p.Length = size
|
||||
p.LargestAcked = largestAcked
|
||||
p.StreamFrames = streamFrames
|
||||
p.Frames = frames
|
||||
p.IsPathMTUProbePacket = isPathMTUProbePacket
|
||||
p.includedInBytesInFlight = true
|
||||
|
||||
pnSpace.history.SentAckElicitingPacket(p)
|
||||
if h.tracer != nil && h.tracer.UpdatedMetrics != nil {
|
||||
h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
|
||||
}
|
||||
if isAckEliciting || !h.peerCompletedAddressValidation {
|
||||
h.setLossDetectionTimer()
|
||||
}
|
||||
h.setLossDetectionTimer()
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) getPacketNumberSpace(encLevel protocol.EncryptionLevel) *packetNumberSpace {
|
||||
@@ -263,31 +305,6 @@ func (h *sentPacketHandler) getPacketNumberSpace(encLevel protocol.EncryptionLev
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) sentPacketImpl(packet *Packet) bool /* is ack-eliciting */ {
|
||||
pnSpace := h.getPacketNumberSpace(packet.EncryptionLevel)
|
||||
|
||||
if h.logger.Debug() && pnSpace.history.HasOutstandingPackets() {
|
||||
for p := utils.Max(0, pnSpace.largestSent+1); p < packet.PacketNumber; p++ {
|
||||
h.logger.Debugf("Skipping packet number %d", p)
|
||||
}
|
||||
}
|
||||
|
||||
pnSpace.largestSent = packet.PacketNumber
|
||||
isAckEliciting := len(packet.Frames) > 0
|
||||
|
||||
if isAckEliciting {
|
||||
pnSpace.lastAckElicitingPacketTime = packet.SendTime
|
||||
packet.includedInBytesInFlight = true
|
||||
h.bytesInFlight += packet.Length
|
||||
if h.numProbesToSend > 0 {
|
||||
h.numProbesToSend--
|
||||
}
|
||||
}
|
||||
h.congestion.OnPacketSent(packet.SendTime, h.bytesInFlight, packet.PacketNumber, packet.Length, isAckEliciting)
|
||||
|
||||
return isAckEliciting
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime time.Time) (bool /* contained 1-RTT packet */, error) {
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
|
||||
@@ -299,8 +316,6 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||
}
|
||||
}
|
||||
|
||||
pnSpace.largestAcked = utils.Max(pnSpace.largestAcked, largestAcked)
|
||||
|
||||
// Servers complete address validation when a protected packet is received.
|
||||
if h.perspective == protocol.PerspectiveClient && !h.peerCompletedAddressValidation &&
|
||||
(encLevel == protocol.EncryptionHandshake || encLevel == protocol.Encryption1RTT) {
|
||||
@@ -330,6 +345,17 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||
h.congestion.MaybeExitSlowStart()
|
||||
}
|
||||
}
|
||||
|
||||
// Only inform the ECN tracker about new 1-RTT ACKs if the ACK increases the largest acked.
|
||||
if encLevel == protocol.Encryption1RTT && h.ecnTracker != nil && largestAcked > pnSpace.largestAcked {
|
||||
congested := h.ecnTracker.HandleNewlyAcked(ackedPackets, int64(ack.ECT0), int64(ack.ECT1), int64(ack.ECNCE))
|
||||
if congested {
|
||||
h.congestion.OnCongestionEvent(largestAcked, 0, priorInFlight)
|
||||
}
|
||||
}
|
||||
|
||||
pnSpace.largestAcked = utils.Max(pnSpace.largestAcked, largestAcked)
|
||||
|
||||
if err := h.detectLostPackets(rcvTime, encLevel); err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -350,18 +376,17 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
|
||||
|
||||
// Reset the pto_count unless the client is unsure if the server has validated the client's address.
|
||||
if h.peerCompletedAddressValidation {
|
||||
if h.tracer != nil && h.ptoCount != 0 {
|
||||
if h.tracer != nil && h.tracer.UpdatedPTOCount != nil && h.ptoCount != 0 {
|
||||
h.tracer.UpdatedPTOCount(0)
|
||||
}
|
||||
h.ptoCount = 0
|
||||
}
|
||||
h.numProbesToSend = 0
|
||||
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.UpdatedMetrics != nil {
|
||||
h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
|
||||
}
|
||||
|
||||
pnSpace.history.DeleteOldPackets(rcvTime)
|
||||
h.setLossDetectionTimer()
|
||||
return acked1RTTPacket, nil
|
||||
}
|
||||
@@ -371,13 +396,13 @@ func (h *sentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNu
|
||||
}
|
||||
|
||||
// Packets are returned in ascending packet number order.
|
||||
func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encLevel protocol.EncryptionLevel) ([]*Packet, error) {
|
||||
func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encLevel protocol.EncryptionLevel) ([]*packet, error) {
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
h.ackedPackets = h.ackedPackets[:0]
|
||||
ackRangeIndex := 0
|
||||
lowestAcked := ack.LowestAcked()
|
||||
largestAcked := ack.LargestAcked()
|
||||
err := pnSpace.history.Iterate(func(p *Packet) (bool, error) {
|
||||
err := pnSpace.history.Iterate(func(p *packet) (bool, error) {
|
||||
// Ignore packets below the lowest acked
|
||||
if p.PacketNumber < lowestAcked {
|
||||
return true, nil
|
||||
@@ -425,14 +450,19 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
|
||||
}
|
||||
|
||||
for _, f := range p.Frames {
|
||||
if f.OnAcked != nil {
|
||||
f.OnAcked(f.Frame)
|
||||
if f.Handler != nil {
|
||||
f.Handler.OnAcked(f.Frame)
|
||||
}
|
||||
}
|
||||
for _, f := range p.StreamFrames {
|
||||
if f.Handler != nil {
|
||||
f.Handler.OnAcked(f.Frame)
|
||||
}
|
||||
}
|
||||
if err := pnSpace.history.Remove(p.PacketNumber); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.AcknowledgedPacket != nil {
|
||||
h.tracer.AcknowledgedPacket(encLevel, p.PacketNumber)
|
||||
}
|
||||
}
|
||||
@@ -525,7 +555,7 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
|
||||
if !lossTime.IsZero() {
|
||||
// Early retransmit timer or time loss detection.
|
||||
h.alarm = lossTime
|
||||
if h.tracer != nil && h.alarm != oldAlarm {
|
||||
if h.tracer != nil && h.tracer.SetLossTimer != nil && h.alarm != oldAlarm {
|
||||
h.tracer.SetLossTimer(logging.TimerTypeACK, encLevel, h.alarm)
|
||||
}
|
||||
return
|
||||
@@ -536,7 +566,7 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
|
||||
h.alarm = time.Time{}
|
||||
if !oldAlarm.IsZero() {
|
||||
h.logger.Debugf("Canceling loss detection timer. Amplification limited.")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.LossTimerCanceled != nil {
|
||||
h.tracer.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
@@ -548,7 +578,7 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
|
||||
h.alarm = time.Time{}
|
||||
if !oldAlarm.IsZero() {
|
||||
h.logger.Debugf("Canceling loss detection timer. No packets in flight.")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.LossTimerCanceled != nil {
|
||||
h.tracer.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
@@ -561,14 +591,14 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
|
||||
if !oldAlarm.IsZero() {
|
||||
h.alarm = time.Time{}
|
||||
h.logger.Debugf("Canceling loss detection timer. No PTO needed..")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.LossTimerCanceled != nil {
|
||||
h.tracer.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
h.alarm = ptoTime
|
||||
if h.tracer != nil && h.alarm != oldAlarm {
|
||||
if h.tracer != nil && h.tracer.SetLossTimer != nil && h.alarm != oldAlarm {
|
||||
h.tracer.SetLossTimer(logging.TimerTypePTO, encLevel, h.alarm)
|
||||
}
|
||||
}
|
||||
@@ -587,30 +617,31 @@ func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.E
|
||||
lostSendTime := now.Add(-lossDelay)
|
||||
|
||||
priorInFlight := h.bytesInFlight
|
||||
return pnSpace.history.Iterate(func(p *Packet) (bool, error) {
|
||||
return pnSpace.history.Iterate(func(p *packet) (bool, error) {
|
||||
if p.PacketNumber > pnSpace.largestAcked {
|
||||
return false, nil
|
||||
}
|
||||
if p.declaredLost || p.skippedPacket {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var packetLost bool
|
||||
if p.SendTime.Before(lostSendTime) {
|
||||
packetLost = true
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tlost packet %d (time threshold)", p.PacketNumber)
|
||||
}
|
||||
if h.tracer != nil {
|
||||
h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossTimeThreshold)
|
||||
if !p.skippedPacket {
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tlost packet %d (time threshold)", p.PacketNumber)
|
||||
}
|
||||
if h.tracer != nil && h.tracer.LostPacket != nil {
|
||||
h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossTimeThreshold)
|
||||
}
|
||||
}
|
||||
} else if pnSpace.largestAcked >= p.PacketNumber+packetThreshold {
|
||||
packetLost = true
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tlost packet %d (reordering threshold)", p.PacketNumber)
|
||||
}
|
||||
if h.tracer != nil {
|
||||
h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossReorderingThreshold)
|
||||
if !p.skippedPacket {
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tlost packet %d (reordering threshold)", p.PacketNumber)
|
||||
}
|
||||
if h.tracer != nil && h.tracer.LostPacket != nil {
|
||||
h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossReorderingThreshold)
|
||||
}
|
||||
}
|
||||
} else if pnSpace.lossTime.IsZero() {
|
||||
// Note: This conditional is only entered once per call
|
||||
@@ -621,12 +652,17 @@ func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.E
|
||||
pnSpace.lossTime = lossTime
|
||||
}
|
||||
if packetLost {
|
||||
p = pnSpace.history.DeclareLost(p)
|
||||
// the bytes in flight need to be reduced no matter if the frames in this packet will be retransmitted
|
||||
h.removeFromBytesInFlight(p)
|
||||
h.queueFramesForRetransmission(p)
|
||||
if !p.IsPathMTUProbePacket {
|
||||
h.congestion.OnPacketLost(p.PacketNumber, p.Length, priorInFlight)
|
||||
pnSpace.history.DeclareLost(p.PacketNumber)
|
||||
if !p.skippedPacket {
|
||||
// the bytes in flight need to be reduced no matter if the frames in this packet will be retransmitted
|
||||
h.removeFromBytesInFlight(p)
|
||||
h.queueFramesForRetransmission(p)
|
||||
if !p.IsPathMTUProbePacket {
|
||||
h.congestion.OnCongestionEvent(p.PacketNumber, p.Length, priorInFlight)
|
||||
}
|
||||
if encLevel == protocol.Encryption1RTT && h.ecnTracker != nil {
|
||||
h.ecnTracker.LostPacket(p.PacketNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
@@ -640,7 +676,7 @@ func (h *sentPacketHandler) OnLossDetectionTimeout() error {
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Loss detection alarm fired in loss timer mode. Loss time: %s", earliestLossTime)
|
||||
}
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.LossTimerExpired != nil {
|
||||
h.tracer.LossTimerExpired(logging.TimerTypeACK, encLevel)
|
||||
}
|
||||
// Early retransmit or time loss detection
|
||||
@@ -677,8 +713,12 @@ func (h *sentPacketHandler) OnLossDetectionTimeout() error {
|
||||
h.logger.Debugf("Loss detection alarm for %s fired in PTO mode. PTO count: %d", encLevel, h.ptoCount)
|
||||
}
|
||||
if h.tracer != nil {
|
||||
h.tracer.LossTimerExpired(logging.TimerTypePTO, encLevel)
|
||||
h.tracer.UpdatedPTOCount(h.ptoCount)
|
||||
if h.tracer.LossTimerExpired != nil {
|
||||
h.tracer.LossTimerExpired(logging.TimerTypePTO, encLevel)
|
||||
}
|
||||
if h.tracer.UpdatedPTOCount != nil {
|
||||
h.tracer.UpdatedPTOCount(h.ptoCount)
|
||||
}
|
||||
}
|
||||
h.numProbesToSend += 2
|
||||
//nolint:exhaustive // We never arm a PTO timer for 0-RTT packets.
|
||||
@@ -689,7 +729,8 @@ func (h *sentPacketHandler) OnLossDetectionTimeout() error {
|
||||
h.ptoMode = SendPTOHandshake
|
||||
case protocol.Encryption1RTT:
|
||||
// skip a packet number in order to elicit an immediate ACK
|
||||
_ = h.PopPacketNumber(protocol.Encryption1RTT)
|
||||
pn := h.PopPacketNumber(protocol.Encryption1RTT)
|
||||
h.getPacketNumberSpace(protocol.Encryption1RTT).history.SkippedPacket(pn)
|
||||
h.ptoMode = SendPTOAppData
|
||||
default:
|
||||
return fmt.Errorf("PTO timer in unexpected encryption level: %s", encLevel)
|
||||
@@ -701,25 +742,37 @@ func (h *sentPacketHandler) GetLossDetectionTimeout() time.Time {
|
||||
return h.alarm
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) ECNMode(isShortHeaderPacket bool) protocol.ECN {
|
||||
if !h.enableECN {
|
||||
return protocol.ECNUnsupported
|
||||
}
|
||||
if !isShortHeaderPacket {
|
||||
return protocol.ECNNon
|
||||
}
|
||||
return h.ecnTracker.Mode()
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) PeekPacketNumber(encLevel protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen) {
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
|
||||
var lowestUnacked protocol.PacketNumber
|
||||
if p := pnSpace.history.FirstOutstanding(); p != nil {
|
||||
lowestUnacked = p.PacketNumber
|
||||
} else {
|
||||
lowestUnacked = pnSpace.largestAcked + 1
|
||||
}
|
||||
|
||||
pn := pnSpace.pns.Peek()
|
||||
return pn, protocol.GetPacketNumberLengthForHeader(pn, lowestUnacked)
|
||||
// See section 17.1 of RFC 9000.
|
||||
return pn, protocol.GetPacketNumberLengthForHeader(pn, pnSpace.largestAcked)
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) PopPacketNumber(encLevel protocol.EncryptionLevel) protocol.PacketNumber {
|
||||
return h.getPacketNumberSpace(encLevel).pns.Pop()
|
||||
pnSpace := h.getPacketNumberSpace(encLevel)
|
||||
skipped, pn := pnSpace.pns.Pop()
|
||||
if skipped {
|
||||
skippedPN := pn - 1
|
||||
pnSpace.history.SkippedPacket(skippedPN)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Skipping packet number %d", skippedPN)
|
||||
}
|
||||
}
|
||||
return pn
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SendMode() SendMode {
|
||||
func (h *sentPacketHandler) SendMode(now time.Time) SendMode {
|
||||
numTrackedPackets := h.appDataPackets.history.Len()
|
||||
if h.initialPackets != nil {
|
||||
numTrackedPackets += h.initialPackets.history.Len()
|
||||
@@ -758,6 +811,9 @@ func (h *sentPacketHandler) SendMode() SendMode {
|
||||
}
|
||||
return SendAck
|
||||
}
|
||||
if !h.congestion.HasPacingBudget(now) {
|
||||
return SendPacingLimited
|
||||
}
|
||||
return SendAny
|
||||
}
|
||||
|
||||
@@ -765,10 +821,6 @@ func (h *sentPacketHandler) TimeUntilSend() time.Time {
|
||||
return h.congestion.TimeUntilSend(h.bytesInFlight)
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) HasPacingBudget() bool {
|
||||
return h.congestion.HasPacingBudget()
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SetMaxDatagramSize(s protocol.ByteCount) {
|
||||
h.congestion.SetMaxDatagramSize(s)
|
||||
}
|
||||
@@ -790,24 +842,32 @@ func (h *sentPacketHandler) QueueProbePacket(encLevel protocol.EncryptionLevel)
|
||||
// TODO: don't declare the packet lost here.
|
||||
// Keep track of acknowledged frames instead.
|
||||
h.removeFromBytesInFlight(p)
|
||||
pnSpace.history.DeclareLost(p)
|
||||
pnSpace.history.DeclareLost(p.PacketNumber)
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) queueFramesForRetransmission(p *Packet) {
|
||||
if len(p.Frames) == 0 {
|
||||
func (h *sentPacketHandler) queueFramesForRetransmission(p *packet) {
|
||||
if len(p.Frames) == 0 && len(p.StreamFrames) == 0 {
|
||||
panic("no frames")
|
||||
}
|
||||
for _, f := range p.Frames {
|
||||
f.OnLost(f.Frame)
|
||||
if f.Handler != nil {
|
||||
f.Handler.OnLost(f.Frame)
|
||||
}
|
||||
}
|
||||
for _, f := range p.StreamFrames {
|
||||
if f.Handler != nil {
|
||||
f.Handler.OnLost(f.Frame)
|
||||
}
|
||||
}
|
||||
p.StreamFrames = nil
|
||||
p.Frames = nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) ResetForRetry() error {
|
||||
func (h *sentPacketHandler) ResetForRetry(now time.Time) error {
|
||||
h.bytesInFlight = 0
|
||||
var firstPacketSendTime time.Time
|
||||
h.initialPackets.history.Iterate(func(p *Packet) (bool, error) {
|
||||
h.initialPackets.history.Iterate(func(p *packet) (bool, error) {
|
||||
if firstPacketSendTime.IsZero() {
|
||||
firstPacketSendTime = p.SendTime
|
||||
}
|
||||
@@ -819,7 +879,7 @@ func (h *sentPacketHandler) ResetForRetry() error {
|
||||
})
|
||||
// All application data packets sent at this point are 0-RTT packets.
|
||||
// In the case of a Retry, we can assume that the server dropped all of them.
|
||||
h.appDataPackets.history.Iterate(func(p *Packet) (bool, error) {
|
||||
h.appDataPackets.history.Iterate(func(p *packet) (bool, error) {
|
||||
if !p.declaredLost && !p.skippedPacket {
|
||||
h.queueFramesForRetransmission(p)
|
||||
}
|
||||
@@ -830,22 +890,23 @@ func (h *sentPacketHandler) ResetForRetry() error {
|
||||
// Otherwise, we don't know which Initial the Retry was sent in response to.
|
||||
if h.ptoCount == 0 {
|
||||
// Don't set the RTT to a value lower than 5ms here.
|
||||
now := time.Now()
|
||||
h.rttStats.UpdateRTT(utils.Max(minRTTAfterRetry, now.Sub(firstPacketSendTime)), 0, now)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
|
||||
}
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.UpdatedMetrics != nil {
|
||||
h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
|
||||
}
|
||||
}
|
||||
h.initialPackets = newPacketNumberSpace(h.initialPackets.pns.Pop(), false, h.rttStats)
|
||||
h.appDataPackets = newPacketNumberSpace(h.appDataPackets.pns.Pop(), true, h.rttStats)
|
||||
h.initialPackets = newPacketNumberSpace(h.initialPackets.pns.Peek(), false)
|
||||
h.appDataPackets = newPacketNumberSpace(h.appDataPackets.pns.Peek(), true)
|
||||
oldAlarm := h.alarm
|
||||
h.alarm = time.Time{}
|
||||
if h.tracer != nil {
|
||||
h.tracer.UpdatedPTOCount(0)
|
||||
if !oldAlarm.IsZero() {
|
||||
if h.tracer.UpdatedPTOCount != nil {
|
||||
h.tracer.UpdatedPTOCount(0)
|
||||
}
|
||||
if !oldAlarm.IsZero() && h.tracer.LossTimerCanceled != nil {
|
||||
h.tracer.LossTimerCanceled()
|
||||
}
|
||||
}
|
||||
@@ -854,6 +915,12 @@ func (h *sentPacketHandler) ResetForRetry() error {
|
||||
}
|
||||
|
||||
func (h *sentPacketHandler) SetHandshakeConfirmed() {
|
||||
if h.initialPackets != nil {
|
||||
panic("didn't drop initial correctly")
|
||||
}
|
||||
if h.handshakePackets != nil {
|
||||
panic("didn't drop handshake correctly")
|
||||
}
|
||||
h.handshakeConfirmed = true
|
||||
// We don't send PTOs for application data packets before the handshake completes.
|
||||
// Make sure the timer is armed now, if necessary.
|
||||
|
||||
248
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
generated
vendored
248
vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
generated
vendored
@@ -2,162 +2,176 @@ package ackhandler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
list "github.com/quic-go/quic-go/internal/utils/linkedlist"
|
||||
)
|
||||
|
||||
type sentPacketHistory struct {
|
||||
rttStats *utils.RTTStats
|
||||
outstandingPacketList *list.List[*Packet]
|
||||
etcPacketList *list.List[*Packet]
|
||||
packetMap map[protocol.PacketNumber]*list.Element[*Packet]
|
||||
highestSent protocol.PacketNumber
|
||||
packets []*packet
|
||||
|
||||
numOutstanding int
|
||||
|
||||
highestPacketNumber protocol.PacketNumber
|
||||
}
|
||||
|
||||
var packetElementPool sync.Pool
|
||||
|
||||
func init() {
|
||||
packetElementPool = *list.NewPool[*Packet]()
|
||||
}
|
||||
|
||||
func newSentPacketHistory(rttStats *utils.RTTStats) *sentPacketHistory {
|
||||
func newSentPacketHistory() *sentPacketHistory {
|
||||
return &sentPacketHistory{
|
||||
rttStats: rttStats,
|
||||
outstandingPacketList: list.NewWithPool[*Packet](&packetElementPool),
|
||||
etcPacketList: list.NewWithPool[*Packet](&packetElementPool),
|
||||
packetMap: make(map[protocol.PacketNumber]*list.Element[*Packet]),
|
||||
highestSent: protocol.InvalidPacketNumber,
|
||||
packets: make([]*packet, 0, 32),
|
||||
highestPacketNumber: protocol.InvalidPacketNumber,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel, t time.Time) {
|
||||
h.registerSentPacket(pn, encLevel, t)
|
||||
func (h *sentPacketHistory) checkSequentialPacketNumberUse(pn protocol.PacketNumber) {
|
||||
if h.highestPacketNumber != protocol.InvalidPacketNumber {
|
||||
if pn != h.highestPacketNumber+1 {
|
||||
panic("non-sequential packet number use")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) SentAckElicitingPacket(p *Packet) {
|
||||
h.registerSentPacket(p.PacketNumber, p.EncryptionLevel, p.SendTime)
|
||||
func (h *sentPacketHistory) SkippedPacket(pn protocol.PacketNumber) {
|
||||
h.checkSequentialPacketNumberUse(pn)
|
||||
h.highestPacketNumber = pn
|
||||
h.packets = append(h.packets, &packet{
|
||||
PacketNumber: pn,
|
||||
skippedPacket: true,
|
||||
})
|
||||
}
|
||||
|
||||
var el *list.Element[*Packet]
|
||||
func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber) {
|
||||
h.checkSequentialPacketNumberUse(pn)
|
||||
h.highestPacketNumber = pn
|
||||
if len(h.packets) > 0 {
|
||||
h.packets = append(h.packets, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) SentAckElicitingPacket(p *packet) {
|
||||
h.checkSequentialPacketNumberUse(p.PacketNumber)
|
||||
h.highestPacketNumber = p.PacketNumber
|
||||
h.packets = append(h.packets, p)
|
||||
if p.outstanding() {
|
||||
el = h.outstandingPacketList.PushBack(p)
|
||||
} else {
|
||||
el = h.etcPacketList.PushBack(p)
|
||||
h.numOutstanding++
|
||||
}
|
||||
h.packetMap[p.PacketNumber] = el
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) registerSentPacket(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel, t time.Time) {
|
||||
if pn <= h.highestSent {
|
||||
panic("non-sequential packet number use")
|
||||
}
|
||||
// Skipped packet numbers.
|
||||
for p := h.highestSent + 1; p < pn; p++ {
|
||||
el := h.etcPacketList.PushBack(&Packet{
|
||||
PacketNumber: p,
|
||||
EncryptionLevel: encLevel,
|
||||
SendTime: t,
|
||||
skippedPacket: true,
|
||||
})
|
||||
h.packetMap[p] = el
|
||||
}
|
||||
h.highestSent = pn
|
||||
}
|
||||
|
||||
// Iterate iterates through all packets.
|
||||
func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) error {
|
||||
cont := true
|
||||
outstandingEl := h.outstandingPacketList.Front()
|
||||
etcEl := h.etcPacketList.Front()
|
||||
var el *list.Element[*Packet]
|
||||
// whichever has the next packet number is returned first
|
||||
for cont {
|
||||
if outstandingEl == nil || (etcEl != nil && etcEl.Value.PacketNumber < outstandingEl.Value.PacketNumber) {
|
||||
el = etcEl
|
||||
} else {
|
||||
el = outstandingEl
|
||||
func (h *sentPacketHistory) Iterate(cb func(*packet) (cont bool, err error)) error {
|
||||
for _, p := range h.packets {
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
if el == nil {
|
||||
return nil
|
||||
}
|
||||
if el == outstandingEl {
|
||||
outstandingEl = outstandingEl.Next()
|
||||
} else {
|
||||
etcEl = etcEl.Next()
|
||||
}
|
||||
var err error
|
||||
cont, err = cb(el.Value)
|
||||
cont, err := cb(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !cont {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FirstOutstanding returns the first outstanding packet.
|
||||
func (h *sentPacketHistory) FirstOutstanding() *Packet {
|
||||
el := h.outstandingPacketList.Front()
|
||||
if el == nil {
|
||||
func (h *sentPacketHistory) FirstOutstanding() *packet {
|
||||
if !h.HasOutstandingPackets() {
|
||||
return nil
|
||||
}
|
||||
return el.Value
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) Len() int {
|
||||
return len(h.packetMap)
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) Remove(p protocol.PacketNumber) error {
|
||||
el, ok := h.packetMap[p]
|
||||
if !ok {
|
||||
return fmt.Errorf("packet %d not found in sent packet history", p)
|
||||
for _, p := range h.packets {
|
||||
if p != nil && p.outstanding() {
|
||||
return p
|
||||
}
|
||||
}
|
||||
el.List().Remove(el)
|
||||
delete(h.packetMap, p)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) HasOutstandingPackets() bool {
|
||||
return h.outstandingPacketList.Len() > 0
|
||||
func (h *sentPacketHistory) Len() int {
|
||||
return len(h.packets)
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) DeleteOldPackets(now time.Time) {
|
||||
maxAge := 3 * h.rttStats.PTO(false)
|
||||
var nextEl *list.Element[*Packet]
|
||||
// we don't iterate outstandingPacketList, as we should not delete outstanding packets.
|
||||
// being outstanding for more than 3*PTO should only happen in the case of drastic RTT changes.
|
||||
for el := h.etcPacketList.Front(); el != nil; el = nextEl {
|
||||
nextEl = el.Next()
|
||||
p := el.Value
|
||||
if p.SendTime.After(now.Add(-maxAge)) {
|
||||
break
|
||||
}
|
||||
delete(h.packetMap, p.PacketNumber)
|
||||
h.etcPacketList.Remove(el)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) DeclareLost(p *Packet) *Packet {
|
||||
el, ok := h.packetMap[p.PacketNumber]
|
||||
func (h *sentPacketHistory) Remove(pn protocol.PacketNumber) error {
|
||||
idx, ok := h.getIndex(pn)
|
||||
if !ok {
|
||||
return nil
|
||||
return fmt.Errorf("packet %d not found in sent packet history", pn)
|
||||
}
|
||||
el.List().Remove(el)
|
||||
p.declaredLost = true
|
||||
// move it to the correct position in the etc list (based on the packet number)
|
||||
for el = h.etcPacketList.Back(); el != nil; el = el.Prev() {
|
||||
if el.Value.PacketNumber < p.PacketNumber {
|
||||
break
|
||||
p := h.packets[idx]
|
||||
if p.outstanding() {
|
||||
h.numOutstanding--
|
||||
if h.numOutstanding < 0 {
|
||||
panic("negative number of outstanding packets")
|
||||
}
|
||||
}
|
||||
if el == nil {
|
||||
el = h.etcPacketList.PushFront(p)
|
||||
} else {
|
||||
el = h.etcPacketList.InsertAfter(p, el)
|
||||
h.packets[idx] = nil
|
||||
// clean up all skipped packets directly before this packet number
|
||||
for idx > 0 {
|
||||
idx--
|
||||
p := h.packets[idx]
|
||||
if p == nil || !p.skippedPacket {
|
||||
break
|
||||
}
|
||||
h.packets[idx] = nil
|
||||
}
|
||||
if idx == 0 {
|
||||
h.cleanupStart()
|
||||
}
|
||||
if len(h.packets) > 0 && h.packets[0] == nil {
|
||||
panic("remove failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getIndex gets the index of packet p in the packets slice.
|
||||
func (h *sentPacketHistory) getIndex(p protocol.PacketNumber) (int, bool) {
|
||||
if len(h.packets) == 0 {
|
||||
return 0, false
|
||||
}
|
||||
first := h.packets[0].PacketNumber
|
||||
if p < first {
|
||||
return 0, false
|
||||
}
|
||||
index := int(p - first)
|
||||
if index > len(h.packets)-1 {
|
||||
return 0, false
|
||||
}
|
||||
return index, true
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) HasOutstandingPackets() bool {
|
||||
return h.numOutstanding > 0
|
||||
}
|
||||
|
||||
// delete all nil entries at the beginning of the packets slice
|
||||
func (h *sentPacketHistory) cleanupStart() {
|
||||
for i, p := range h.packets {
|
||||
if p != nil {
|
||||
h.packets = h.packets[i:]
|
||||
return
|
||||
}
|
||||
}
|
||||
h.packets = h.packets[:0]
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) LowestPacketNumber() protocol.PacketNumber {
|
||||
if len(h.packets) == 0 {
|
||||
return protocol.InvalidPacketNumber
|
||||
}
|
||||
return h.packets[0].PacketNumber
|
||||
}
|
||||
|
||||
func (h *sentPacketHistory) DeclareLost(pn protocol.PacketNumber) {
|
||||
idx, ok := h.getIndex(pn)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
p := h.packets[idx]
|
||||
if p.outstanding() {
|
||||
h.numOutstanding--
|
||||
if h.numOutstanding < 0 {
|
||||
panic("negative number of outstanding packets")
|
||||
}
|
||||
}
|
||||
h.packets[idx] = nil
|
||||
if idx == 0 {
|
||||
h.cleanupStart()
|
||||
}
|
||||
h.packetMap[p.PacketNumber] = el
|
||||
return el.Value
|
||||
}
|
||||
|
||||
16
vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
generated
vendored
16
vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
generated
vendored
@@ -56,7 +56,7 @@ type cubicSender struct {
|
||||
maxDatagramSize protocol.ByteCount
|
||||
|
||||
lastState logging.CongestionState
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -70,7 +70,7 @@ func NewCubicSender(
|
||||
rttStats *utils.RTTStats,
|
||||
initialMaxDatagramSize protocol.ByteCount,
|
||||
reno bool,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
) *cubicSender {
|
||||
return newCubicSender(
|
||||
clock,
|
||||
@@ -90,7 +90,7 @@ func newCubicSender(
|
||||
initialMaxDatagramSize,
|
||||
initialCongestionWindow,
|
||||
initialMaxCongestionWindow protocol.ByteCount,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
) *cubicSender {
|
||||
c := &cubicSender{
|
||||
rttStats: rttStats,
|
||||
@@ -108,7 +108,7 @@ func newCubicSender(
|
||||
maxDatagramSize: initialMaxDatagramSize,
|
||||
}
|
||||
c.pacer = newPacer(c.BandwidthEstimate)
|
||||
if c.tracer != nil {
|
||||
if c.tracer != nil && c.tracer.UpdatedCongestionState != nil {
|
||||
c.lastState = logging.CongestionStateSlowStart
|
||||
c.tracer.UpdatedCongestionState(logging.CongestionStateSlowStart)
|
||||
}
|
||||
@@ -120,8 +120,8 @@ func (c *cubicSender) TimeUntilSend(_ protocol.ByteCount) time.Time {
|
||||
return c.pacer.TimeUntilSend()
|
||||
}
|
||||
|
||||
func (c *cubicSender) HasPacingBudget() bool {
|
||||
return c.pacer.Budget(c.clock.Now()) >= c.maxDatagramSize
|
||||
func (c *cubicSender) HasPacingBudget(now time.Time) bool {
|
||||
return c.pacer.Budget(now) >= c.maxDatagramSize
|
||||
}
|
||||
|
||||
func (c *cubicSender) maxCongestionWindow() protocol.ByteCount {
|
||||
@@ -188,7 +188,7 @@ func (c *cubicSender) OnPacketAcked(
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cubicSender) OnPacketLost(packetNumber protocol.PacketNumber, lostBytes, priorInFlight protocol.ByteCount) {
|
||||
func (c *cubicSender) OnCongestionEvent(packetNumber protocol.PacketNumber, lostBytes, priorInFlight protocol.ByteCount) {
|
||||
// TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
|
||||
// already sent should be treated as a single loss event, since it's expected.
|
||||
if packetNumber <= c.largestSentAtLastCutback {
|
||||
@@ -296,7 +296,7 @@ func (c *cubicSender) OnConnectionMigration() {
|
||||
}
|
||||
|
||||
func (c *cubicSender) maybeTraceStateChange(new logging.CongestionState) {
|
||||
if c.tracer == nil || new == c.lastState {
|
||||
if c.tracer == nil || c.tracer.UpdatedCongestionState == nil || new == c.lastState {
|
||||
return
|
||||
}
|
||||
c.tracer.UpdatedCongestionState(new)
|
||||
|
||||
4
vendor/github.com/quic-go/quic-go/internal/congestion/interface.go
generated
vendored
4
vendor/github.com/quic-go/quic-go/internal/congestion/interface.go
generated
vendored
@@ -9,12 +9,12 @@ import (
|
||||
// A SendAlgorithm performs congestion control
|
||||
type SendAlgorithm interface {
|
||||
TimeUntilSend(bytesInFlight protocol.ByteCount) time.Time
|
||||
HasPacingBudget() bool
|
||||
HasPacingBudget(now time.Time) bool
|
||||
OnPacketSent(sentTime time.Time, bytesInFlight protocol.ByteCount, packetNumber protocol.PacketNumber, bytes protocol.ByteCount, isRetransmittable bool)
|
||||
CanSend(bytesInFlight protocol.ByteCount) bool
|
||||
MaybeExitSlowStart()
|
||||
OnPacketAcked(number protocol.PacketNumber, ackedBytes protocol.ByteCount, priorInFlight protocol.ByteCount, eventTime time.Time)
|
||||
OnPacketLost(number protocol.PacketNumber, lostBytes protocol.ByteCount, priorInFlight protocol.ByteCount)
|
||||
OnCongestionEvent(number protocol.PacketNumber, lostBytes protocol.ByteCount, priorInFlight protocol.ByteCount)
|
||||
OnRetransmissionTimeout(packetsRetransmitted bool)
|
||||
SetMaxDatagramSize(protocol.ByteCount)
|
||||
}
|
||||
|
||||
19
vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
generated
vendored
19
vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
generated
vendored
@@ -1,7 +1,6 @@
|
||||
package congestion
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
@@ -26,7 +25,7 @@ func newPacer(getBandwidth func() Bandwidth) *pacer {
|
||||
bw := uint64(getBandwidth() / BytesPerSecond)
|
||||
// Use a slightly higher value than the actual measured bandwidth.
|
||||
// RTT variations then won't result in under-utilization of the congestion window.
|
||||
// Ultimately, this will result in sending packets as acknowledgments are received rather than when timers fire,
|
||||
// Ultimately, this will result in sending packets as acknowledgments are received rather than when timers fire,
|
||||
// provided the congestion window is fully utilized and acknowledgments arrive at regular intervals.
|
||||
return bw * 5 / 4
|
||||
},
|
||||
@@ -37,7 +36,7 @@ func newPacer(getBandwidth func() Bandwidth) *pacer {
|
||||
|
||||
func (p *pacer) SentPacket(sendTime time.Time, size protocol.ByteCount) {
|
||||
budget := p.Budget(sendTime)
|
||||
if size > budget {
|
||||
if size >= budget {
|
||||
p.budgetAtLastSent = 0
|
||||
} else {
|
||||
p.budgetAtLastSent = budget - size
|
||||
@@ -69,10 +68,16 @@ func (p *pacer) TimeUntilSend() time.Time {
|
||||
if p.budgetAtLastSent >= p.maxDatagramSize {
|
||||
return time.Time{}
|
||||
}
|
||||
return p.lastSentTime.Add(utils.Max(
|
||||
protocol.MinPacingDelay,
|
||||
time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.adjustedBandwidth())))*time.Nanosecond,
|
||||
))
|
||||
diff := 1e9 * uint64(p.maxDatagramSize-p.budgetAtLastSent)
|
||||
bw := p.adjustedBandwidth()
|
||||
// We might need to round up this value.
|
||||
// Otherwise, we might have a budget (slightly) smaller than the datagram size when the timer expires.
|
||||
d := diff / bw
|
||||
// this is effectively a math.Ceil, but using only integer math
|
||||
if diff%bw > 0 {
|
||||
d++
|
||||
}
|
||||
return p.lastSentTime.Add(utils.Max(protocol.MinPacingDelay, time.Duration(d)*time.Nanosecond))
|
||||
}
|
||||
|
||||
func (p *pacer) SetMaxDatagramSize(s protocol.ByteCount) {
|
||||
|
||||
69
vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
generated
vendored
69
vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
generated
vendored
@@ -5,11 +5,10 @@ import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
func createAEAD(suite *qtls.CipherSuiteTLS13, trafficSecret []byte, v protocol.VersionNumber) cipher.AEAD {
|
||||
func createAEAD(suite *cipherSuite, trafficSecret []byte, v protocol.VersionNumber) cipher.AEAD {
|
||||
keyLabel := hkdfLabelKeyV1
|
||||
ivLabel := hkdfLabelIVV1
|
||||
if v == protocol.Version2 {
|
||||
@@ -93,69 +92,3 @@ func (o *longHeaderOpener) Open(dst, src []byte, pn protocol.PacketNumber, ad []
|
||||
func (o *longHeaderOpener) DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte) {
|
||||
o.headerProtector.DecryptHeader(sample, firstByte, pnBytes)
|
||||
}
|
||||
|
||||
type handshakeSealer struct {
|
||||
LongHeaderSealer
|
||||
|
||||
dropInitialKeys func()
|
||||
dropped bool
|
||||
}
|
||||
|
||||
func newHandshakeSealer(
|
||||
aead cipher.AEAD,
|
||||
headerProtector headerProtector,
|
||||
dropInitialKeys func(),
|
||||
perspective protocol.Perspective,
|
||||
) LongHeaderSealer {
|
||||
sealer := newLongHeaderSealer(aead, headerProtector)
|
||||
// The client drops Initial keys when sending the first Handshake packet.
|
||||
if perspective == protocol.PerspectiveServer {
|
||||
return sealer
|
||||
}
|
||||
return &handshakeSealer{
|
||||
LongHeaderSealer: sealer,
|
||||
dropInitialKeys: dropInitialKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *handshakeSealer) Seal(dst, src []byte, pn protocol.PacketNumber, ad []byte) []byte {
|
||||
data := s.LongHeaderSealer.Seal(dst, src, pn, ad)
|
||||
if !s.dropped {
|
||||
s.dropInitialKeys()
|
||||
s.dropped = true
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
type handshakeOpener struct {
|
||||
LongHeaderOpener
|
||||
|
||||
dropInitialKeys func()
|
||||
dropped bool
|
||||
}
|
||||
|
||||
func newHandshakeOpener(
|
||||
aead cipher.AEAD,
|
||||
headerProtector headerProtector,
|
||||
dropInitialKeys func(),
|
||||
perspective protocol.Perspective,
|
||||
) LongHeaderOpener {
|
||||
opener := newLongHeaderOpener(aead, headerProtector)
|
||||
// The server drops Initial keys when first successfully processing a Handshake packet.
|
||||
if perspective == protocol.PerspectiveClient {
|
||||
return opener
|
||||
}
|
||||
return &handshakeOpener{
|
||||
LongHeaderOpener: opener,
|
||||
dropInitialKeys: dropInitialKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *handshakeOpener) Open(dst, src []byte, pn protocol.PacketNumber, ad []byte) ([]byte, error) {
|
||||
dec, err := o.LongHeaderOpener.Open(dst, src, pn, ad)
|
||||
if err == nil && !o.dropped {
|
||||
o.dropInitialKeys()
|
||||
o.dropped = true
|
||||
}
|
||||
return dec, err
|
||||
}
|
||||
|
||||
104
vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
generated
vendored
Normal file
104
vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
// These cipher suite implementations are copied from the standard library crypto/tls package.
|
||||
|
||||
const aeadNonceLength = 12
|
||||
|
||||
type cipherSuite struct {
|
||||
ID uint16
|
||||
Hash crypto.Hash
|
||||
KeyLen int
|
||||
AEAD func(key, nonceMask []byte) cipher.AEAD
|
||||
}
|
||||
|
||||
func (s cipherSuite) IVLen() int { return aeadNonceLength }
|
||||
|
||||
func getCipherSuite(id uint16) *cipherSuite {
|
||||
switch id {
|
||||
case tls.TLS_AES_128_GCM_SHA256:
|
||||
return &cipherSuite{ID: tls.TLS_AES_128_GCM_SHA256, Hash: crypto.SHA256, KeyLen: 16, AEAD: aeadAESGCMTLS13}
|
||||
case tls.TLS_CHACHA20_POLY1305_SHA256:
|
||||
return &cipherSuite{ID: tls.TLS_CHACHA20_POLY1305_SHA256, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadChaCha20Poly1305}
|
||||
case tls.TLS_AES_256_GCM_SHA384:
|
||||
return &cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA384, KeyLen: 32, AEAD: aeadAESGCMTLS13}
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown cypher suite: %d", id))
|
||||
}
|
||||
}
|
||||
|
||||
func aeadAESGCMTLS13(key, nonceMask []byte) cipher.AEAD {
|
||||
if len(nonceMask) != aeadNonceLength {
|
||||
panic("tls: internal error: wrong nonce length")
|
||||
}
|
||||
aes, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
aead, err := cipher.NewGCM(aes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ret := &xorNonceAEAD{aead: aead}
|
||||
copy(ret.nonceMask[:], nonceMask)
|
||||
return ret
|
||||
}
|
||||
|
||||
func aeadChaCha20Poly1305(key, nonceMask []byte) cipher.AEAD {
|
||||
if len(nonceMask) != aeadNonceLength {
|
||||
panic("tls: internal error: wrong nonce length")
|
||||
}
|
||||
aead, err := chacha20poly1305.New(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ret := &xorNonceAEAD{aead: aead}
|
||||
copy(ret.nonceMask[:], nonceMask)
|
||||
return ret
|
||||
}
|
||||
|
||||
// xorNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
|
||||
// before each call.
|
||||
type xorNonceAEAD struct {
|
||||
nonceMask [aeadNonceLength]byte
|
||||
aead cipher.AEAD
|
||||
}
|
||||
|
||||
func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
|
||||
func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
||||
func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
|
||||
|
||||
func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
|
||||
for i, b := range nonce {
|
||||
f.nonceMask[4+i] ^= b
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
21
vendor/github.com/quic-go/quic-go/internal/handshake/conn.go
generated
vendored
Normal file
21
vendor/github.com/quic-go/quic-go/internal/handshake/conn.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type conn struct {
|
||||
localAddr, remoteAddr net.Addr
|
||||
}
|
||||
|
||||
var _ net.Conn = &conn{}
|
||||
|
||||
func (c *conn) Read([]byte) (int, error) { return 0, nil }
|
||||
func (c *conn) Write([]byte) (int, error) { return 0, nil }
|
||||
func (c *conn) Close() error { return nil }
|
||||
func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr }
|
||||
func (c *conn) LocalAddr() net.Addr { return c.localAddr }
|
||||
func (c *conn) SetReadDeadline(time.Time) error { return nil }
|
||||
func (c *conn) SetWriteDeadline(time.Time) error { return nil }
|
||||
func (c *conn) SetDeadline(time.Time) error { return nil }
|
||||
710
vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
generated
vendored
710
vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
generated
vendored
@@ -6,10 +6,10 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
@@ -25,102 +25,25 @@ type quicVersionContextKey struct{}
|
||||
|
||||
var QUICVersionContextKey = &quicVersionContextKey{}
|
||||
|
||||
// TLS unexpected_message alert
|
||||
const alertUnexpectedMessage uint8 = 10
|
||||
|
||||
type messageType uint8
|
||||
|
||||
// TLS handshake message types.
|
||||
const (
|
||||
typeClientHello messageType = 1
|
||||
typeServerHello messageType = 2
|
||||
typeNewSessionTicket messageType = 4
|
||||
typeEncryptedExtensions messageType = 8
|
||||
typeCertificate messageType = 11
|
||||
typeCertificateRequest messageType = 13
|
||||
typeCertificateVerify messageType = 15
|
||||
typeFinished messageType = 20
|
||||
)
|
||||
|
||||
func (m messageType) String() string {
|
||||
switch m {
|
||||
case typeClientHello:
|
||||
return "ClientHello"
|
||||
case typeServerHello:
|
||||
return "ServerHello"
|
||||
case typeNewSessionTicket:
|
||||
return "NewSessionTicket"
|
||||
case typeEncryptedExtensions:
|
||||
return "EncryptedExtensions"
|
||||
case typeCertificate:
|
||||
return "Certificate"
|
||||
case typeCertificateRequest:
|
||||
return "CertificateRequest"
|
||||
case typeCertificateVerify:
|
||||
return "CertificateVerify"
|
||||
case typeFinished:
|
||||
return "Finished"
|
||||
default:
|
||||
return fmt.Sprintf("unknown message type: %d", m)
|
||||
}
|
||||
}
|
||||
|
||||
const clientSessionStateRevision = 3
|
||||
|
||||
type conn struct {
|
||||
localAddr, remoteAddr net.Addr
|
||||
}
|
||||
|
||||
var _ net.Conn = &conn{}
|
||||
|
||||
func newConn(local, remote net.Addr) net.Conn {
|
||||
return &conn{
|
||||
localAddr: local,
|
||||
remoteAddr: remote,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) Read([]byte) (int, error) { return 0, nil }
|
||||
func (c *conn) Write([]byte) (int, error) { return 0, nil }
|
||||
func (c *conn) Close() error { return nil }
|
||||
func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr }
|
||||
func (c *conn) LocalAddr() net.Addr { return c.localAddr }
|
||||
func (c *conn) SetReadDeadline(time.Time) error { return nil }
|
||||
func (c *conn) SetWriteDeadline(time.Time) error { return nil }
|
||||
func (c *conn) SetDeadline(time.Time) error { return nil }
|
||||
|
||||
type cryptoSetup struct {
|
||||
tlsConf *tls.Config
|
||||
extraConf *qtls.ExtraConfig
|
||||
conn *qtls.Conn
|
||||
tlsConf *tls.Config
|
||||
conn *qtls.QUICConn
|
||||
|
||||
events []Event
|
||||
|
||||
version protocol.VersionNumber
|
||||
|
||||
messageChan chan []byte
|
||||
isReadingHandshakeMessage chan struct{}
|
||||
readFirstHandshakeMessage bool
|
||||
|
||||
ourParams *wire.TransportParameters
|
||||
peerParams *wire.TransportParameters
|
||||
paramsChan <-chan []byte
|
||||
|
||||
runner handshakeRunner
|
||||
|
||||
alertChan chan uint8
|
||||
// handshakeDone is closed as soon as the go routine running qtls.Handshake() returns
|
||||
handshakeDone chan struct{}
|
||||
// is closed when Close() is called
|
||||
closeChan chan struct{}
|
||||
|
||||
zeroRTTParameters *wire.TransportParameters
|
||||
clientHelloWritten bool
|
||||
clientHelloWrittenChan chan struct{} // is closed as soon as the ClientHello is written
|
||||
zeroRTTParametersChan chan<- *wire.TransportParameters
|
||||
allow0RTT bool
|
||||
zeroRTTParameters *wire.TransportParameters
|
||||
allow0RTT bool
|
||||
|
||||
rttStats *utils.RTTStats
|
||||
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
logger utils.Logger
|
||||
|
||||
perspective protocol.Perspective
|
||||
@@ -129,169 +52,152 @@ type cryptoSetup struct {
|
||||
|
||||
handshakeCompleteTime time.Time
|
||||
|
||||
readEncLevel protocol.EncryptionLevel
|
||||
writeEncLevel protocol.EncryptionLevel
|
||||
|
||||
zeroRTTOpener LongHeaderOpener // only set for the server
|
||||
zeroRTTSealer LongHeaderSealer // only set for the client
|
||||
|
||||
initialStream io.Writer
|
||||
initialOpener LongHeaderOpener
|
||||
initialSealer LongHeaderSealer
|
||||
|
||||
handshakeStream io.Writer
|
||||
handshakeOpener LongHeaderOpener
|
||||
handshakeSealer LongHeaderSealer
|
||||
|
||||
used0RTT atomic.Bool
|
||||
|
||||
aead *updatableAEAD
|
||||
has1RTTSealer bool
|
||||
has1RTTOpener bool
|
||||
}
|
||||
|
||||
var (
|
||||
_ qtls.RecordLayer = &cryptoSetup{}
|
||||
_ CryptoSetup = &cryptoSetup{}
|
||||
)
|
||||
var _ CryptoSetup = &cryptoSetup{}
|
||||
|
||||
// NewCryptoSetupClient creates a new crypto setup for the client
|
||||
func NewCryptoSetupClient(
|
||||
initialStream io.Writer,
|
||||
handshakeStream io.Writer,
|
||||
connID protocol.ConnectionID,
|
||||
localAddr net.Addr,
|
||||
remoteAddr net.Addr,
|
||||
tp *wire.TransportParameters,
|
||||
runner handshakeRunner,
|
||||
tlsConf *tls.Config,
|
||||
enable0RTT bool,
|
||||
rttStats *utils.RTTStats,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
version protocol.VersionNumber,
|
||||
) (CryptoSetup, <-chan *wire.TransportParameters /* ClientHello written. Receive nil for non-0-RTT */) {
|
||||
cs, clientHelloWritten := newCryptoSetup(
|
||||
initialStream,
|
||||
handshakeStream,
|
||||
) CryptoSetup {
|
||||
cs := newCryptoSetup(
|
||||
connID,
|
||||
tp,
|
||||
runner,
|
||||
tlsConf,
|
||||
enable0RTT,
|
||||
rttStats,
|
||||
tracer,
|
||||
logger,
|
||||
protocol.PerspectiveClient,
|
||||
version,
|
||||
)
|
||||
cs.conn = qtls.Client(newConn(localAddr, remoteAddr), cs.tlsConf, cs.extraConf)
|
||||
return cs, clientHelloWritten
|
||||
|
||||
tlsConf = tlsConf.Clone()
|
||||
tlsConf.MinVersion = tls.VersionTLS13
|
||||
quicConf := &qtls.QUICConfig{TLSConfig: tlsConf}
|
||||
qtls.SetupConfigForClient(quicConf, cs.marshalDataForSessionState, cs.handleDataFromSessionState)
|
||||
cs.tlsConf = tlsConf
|
||||
cs.allow0RTT = enable0RTT
|
||||
|
||||
cs.conn = qtls.QUICClient(quicConf)
|
||||
cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient))
|
||||
|
||||
return cs
|
||||
}
|
||||
|
||||
// NewCryptoSetupServer creates a new crypto setup for the server
|
||||
func NewCryptoSetupServer(
|
||||
initialStream io.Writer,
|
||||
handshakeStream io.Writer,
|
||||
connID protocol.ConnectionID,
|
||||
localAddr net.Addr,
|
||||
remoteAddr net.Addr,
|
||||
localAddr, remoteAddr net.Addr,
|
||||
tp *wire.TransportParameters,
|
||||
runner handshakeRunner,
|
||||
tlsConf *tls.Config,
|
||||
allow0RTT bool,
|
||||
rttStats *utils.RTTStats,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
version protocol.VersionNumber,
|
||||
) CryptoSetup {
|
||||
cs, _ := newCryptoSetup(
|
||||
initialStream,
|
||||
handshakeStream,
|
||||
cs := newCryptoSetup(
|
||||
connID,
|
||||
tp,
|
||||
runner,
|
||||
tlsConf,
|
||||
allow0RTT,
|
||||
rttStats,
|
||||
tracer,
|
||||
logger,
|
||||
protocol.PerspectiveServer,
|
||||
version,
|
||||
)
|
||||
cs.conn = qtls.Server(newConn(localAddr, remoteAddr), cs.tlsConf, cs.extraConf)
|
||||
cs.allow0RTT = allow0RTT
|
||||
|
||||
quicConf := &qtls.QUICConfig{TLSConfig: tlsConf}
|
||||
qtls.SetupConfigForServer(quicConf, cs.allow0RTT, cs.getDataForSessionTicket, cs.handleSessionTicket)
|
||||
addConnToClientHelloInfo(quicConf.TLSConfig, localAddr, remoteAddr)
|
||||
|
||||
cs.tlsConf = quicConf.TLSConfig
|
||||
cs.conn = qtls.QUICServer(quicConf)
|
||||
|
||||
return cs
|
||||
}
|
||||
|
||||
// The tls.Config contains two callbacks that pass in a tls.ClientHelloInfo.
|
||||
// Since crypto/tls doesn't do it, we need to make sure to set the Conn field with a fake net.Conn
|
||||
// that allows the caller to get the local and the remote address.
|
||||
func addConnToClientHelloInfo(conf *tls.Config, localAddr, remoteAddr net.Addr) {
|
||||
if conf.GetConfigForClient != nil {
|
||||
gcfc := conf.GetConfigForClient
|
||||
conf.GetConfigForClient = func(info *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr}
|
||||
c, err := gcfc(info)
|
||||
if c != nil {
|
||||
c = c.Clone()
|
||||
// This won't be necessary anymore once https://github.com/golang/go/issues/63722 is accepted.
|
||||
c.MinVersion = tls.VersionTLS13
|
||||
// We're returning a tls.Config here, so we need to apply this recursively.
|
||||
addConnToClientHelloInfo(c, localAddr, remoteAddr)
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
}
|
||||
if conf.GetCertificate != nil {
|
||||
gc := conf.GetCertificate
|
||||
conf.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr}
|
||||
return gc(info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newCryptoSetup(
|
||||
initialStream io.Writer,
|
||||
handshakeStream io.Writer,
|
||||
connID protocol.ConnectionID,
|
||||
tp *wire.TransportParameters,
|
||||
runner handshakeRunner,
|
||||
tlsConf *tls.Config,
|
||||
enable0RTT bool,
|
||||
rttStats *utils.RTTStats,
|
||||
tracer logging.ConnectionTracer,
|
||||
tracer *logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
perspective protocol.Perspective,
|
||||
version protocol.VersionNumber,
|
||||
) (*cryptoSetup, <-chan *wire.TransportParameters /* ClientHello written. Receive nil for non-0-RTT */) {
|
||||
) *cryptoSetup {
|
||||
initialSealer, initialOpener := NewInitialAEAD(connID, perspective, version)
|
||||
if tracer != nil {
|
||||
if tracer != nil && tracer.UpdatedKeyFromTLS != nil {
|
||||
tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveClient)
|
||||
tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveServer)
|
||||
}
|
||||
extHandler := newExtensionHandler(tp.Marshal(perspective), perspective, version)
|
||||
zeroRTTParametersChan := make(chan *wire.TransportParameters, 1)
|
||||
cs := &cryptoSetup{
|
||||
tlsConf: tlsConf,
|
||||
initialStream: initialStream,
|
||||
initialSealer: initialSealer,
|
||||
initialOpener: initialOpener,
|
||||
handshakeStream: handshakeStream,
|
||||
aead: newUpdatableAEAD(rttStats, tracer, logger, version),
|
||||
readEncLevel: protocol.EncryptionInitial,
|
||||
writeEncLevel: protocol.EncryptionInitial,
|
||||
runner: runner,
|
||||
allow0RTT: enable0RTT,
|
||||
ourParams: tp,
|
||||
paramsChan: extHandler.TransportParameters(),
|
||||
rttStats: rttStats,
|
||||
tracer: tracer,
|
||||
logger: logger,
|
||||
perspective: perspective,
|
||||
handshakeDone: make(chan struct{}),
|
||||
alertChan: make(chan uint8),
|
||||
clientHelloWrittenChan: make(chan struct{}),
|
||||
zeroRTTParametersChan: zeroRTTParametersChan,
|
||||
messageChan: make(chan []byte, 1),
|
||||
isReadingHandshakeMessage: make(chan struct{}),
|
||||
closeChan: make(chan struct{}),
|
||||
version: version,
|
||||
return &cryptoSetup{
|
||||
initialSealer: initialSealer,
|
||||
initialOpener: initialOpener,
|
||||
aead: newUpdatableAEAD(rttStats, tracer, logger, version),
|
||||
events: make([]Event, 0, 16),
|
||||
ourParams: tp,
|
||||
rttStats: rttStats,
|
||||
tracer: tracer,
|
||||
logger: logger,
|
||||
perspective: perspective,
|
||||
version: version,
|
||||
}
|
||||
var maxEarlyData uint32
|
||||
if enable0RTT {
|
||||
maxEarlyData = math.MaxUint32
|
||||
}
|
||||
cs.extraConf = &qtls.ExtraConfig{
|
||||
GetExtensions: extHandler.GetExtensions,
|
||||
ReceivedExtensions: extHandler.ReceivedExtensions,
|
||||
AlternativeRecordLayer: cs,
|
||||
EnforceNextProtoSelection: true,
|
||||
MaxEarlyData: maxEarlyData,
|
||||
Accept0RTT: cs.accept0RTT,
|
||||
Rejected0RTT: cs.rejected0RTT,
|
||||
Enable0RTT: enable0RTT,
|
||||
GetAppDataForSessionState: cs.marshalDataForSessionState,
|
||||
SetAppDataFromSessionState: cs.handleDataFromSessionState,
|
||||
}
|
||||
return cs, zeroRTTParametersChan
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) ChangeConnectionID(id protocol.ConnectionID) {
|
||||
initialSealer, initialOpener := NewInitialAEAD(id, h.perspective, h.version)
|
||||
h.initialSealer = initialSealer
|
||||
h.initialOpener = initialOpener
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveClient)
|
||||
h.tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveServer)
|
||||
}
|
||||
@@ -301,142 +207,109 @@ func (h *cryptoSetup) SetLargest1RTTAcked(pn protocol.PacketNumber) error {
|
||||
return h.aead.SetLargestAcked(pn)
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) RunHandshake() {
|
||||
// Handle errors that might occur when HandleData() is called.
|
||||
handshakeComplete := make(chan struct{})
|
||||
handshakeErrChan := make(chan error, 1)
|
||||
go func() {
|
||||
defer close(h.handshakeDone)
|
||||
if err := h.conn.HandshakeContext(context.WithValue(context.Background(), QUICVersionContextKey, h.version)); err != nil {
|
||||
handshakeErrChan <- err
|
||||
return
|
||||
func (h *cryptoSetup) StartHandshake() error {
|
||||
err := h.conn.Start(context.WithValue(context.Background(), QUICVersionContextKey, h.version))
|
||||
if err != nil {
|
||||
return wrapError(err)
|
||||
}
|
||||
for {
|
||||
ev := h.conn.NextEvent()
|
||||
done, err := h.handleEvent(ev)
|
||||
if err != nil {
|
||||
return wrapError(err)
|
||||
}
|
||||
close(handshakeComplete)
|
||||
}()
|
||||
|
||||
if done {
|
||||
break
|
||||
}
|
||||
}
|
||||
if h.perspective == protocol.PerspectiveClient {
|
||||
select {
|
||||
case err := <-handshakeErrChan:
|
||||
h.onError(0, err.Error())
|
||||
return
|
||||
case <-h.clientHelloWrittenChan:
|
||||
if h.zeroRTTSealer != nil && h.zeroRTTParameters != nil {
|
||||
h.logger.Debugf("Doing 0-RTT.")
|
||||
h.events = append(h.events, Event{Kind: EventRestoredTransportParameters, TransportParameters: h.zeroRTTParameters})
|
||||
} else {
|
||||
h.logger.Debugf("Not doing 0-RTT. Has sealer: %t, has params: %t", h.zeroRTTSealer != nil, h.zeroRTTParameters != nil)
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case <-handshakeComplete: // return when the handshake is done
|
||||
h.mutex.Lock()
|
||||
h.handshakeCompleteTime = time.Now()
|
||||
h.mutex.Unlock()
|
||||
h.runner.OnHandshakeComplete()
|
||||
case <-h.closeChan:
|
||||
// wait until the Handshake() go routine has returned
|
||||
<-h.handshakeDone
|
||||
case alert := <-h.alertChan:
|
||||
handshakeErr := <-handshakeErrChan
|
||||
h.onError(alert, handshakeErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) onError(alert uint8, message string) {
|
||||
var err error
|
||||
if alert == 0 {
|
||||
err = &qerr.TransportError{ErrorCode: qerr.InternalError, ErrorMessage: message}
|
||||
} else {
|
||||
err = qerr.NewLocalCryptoError(alert, message)
|
||||
}
|
||||
h.runner.OnError(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the crypto setup.
|
||||
// It aborts the handshake, if it is still running.
|
||||
// It must only be called once.
|
||||
func (h *cryptoSetup) Close() error {
|
||||
close(h.closeChan)
|
||||
// wait until qtls.Handshake() actually returned
|
||||
<-h.handshakeDone
|
||||
return nil
|
||||
return h.conn.Close()
|
||||
}
|
||||
|
||||
// handleMessage handles a TLS handshake message.
|
||||
// HandleMessage handles a TLS handshake message.
|
||||
// It is called by the crypto streams when a new message is available.
|
||||
// It returns if it is done with messages on the same encryption level.
|
||||
func (h *cryptoSetup) HandleMessage(data []byte, encLevel protocol.EncryptionLevel) bool /* stream finished */ {
|
||||
msgType := messageType(data[0])
|
||||
h.logger.Debugf("Received %s message (%d bytes, encryption level: %s)", msgType, len(data), encLevel)
|
||||
if err := h.checkEncryptionLevel(msgType, encLevel); err != nil {
|
||||
h.onError(alertUnexpectedMessage, err.Error())
|
||||
return false
|
||||
}
|
||||
if encLevel != protocol.Encryption1RTT {
|
||||
select {
|
||||
case h.messageChan <- data:
|
||||
case <-h.handshakeDone: // handshake errored, nobody is going to consume this message
|
||||
return false
|
||||
}
|
||||
}
|
||||
if encLevel == protocol.Encryption1RTT {
|
||||
h.messageChan <- data
|
||||
h.handlePostHandshakeMessage()
|
||||
return false
|
||||
}
|
||||
readLoop:
|
||||
for {
|
||||
select {
|
||||
case data := <-h.paramsChan:
|
||||
if data == nil {
|
||||
h.onError(0x6d, "missing quic_transport_parameters extension")
|
||||
} else {
|
||||
h.handleTransportParameters(data)
|
||||
}
|
||||
case <-h.isReadingHandshakeMessage:
|
||||
break readLoop
|
||||
case <-h.handshakeDone:
|
||||
break readLoop
|
||||
case <-h.closeChan:
|
||||
break readLoop
|
||||
}
|
||||
}
|
||||
// We're done with the Initial encryption level after processing a ClientHello / ServerHello,
|
||||
// but only if a handshake opener and sealer was created.
|
||||
// Otherwise, a HelloRetryRequest was performed.
|
||||
// We're done with the Handshake encryption level after processing the Finished message.
|
||||
return ((msgType == typeClientHello || msgType == typeServerHello) && h.handshakeOpener != nil && h.handshakeSealer != nil) ||
|
||||
msgType == typeFinished
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) checkEncryptionLevel(msgType messageType, encLevel protocol.EncryptionLevel) error {
|
||||
var expected protocol.EncryptionLevel
|
||||
switch msgType {
|
||||
case typeClientHello, typeServerHello:
|
||||
expected = protocol.EncryptionInitial
|
||||
case typeEncryptedExtensions,
|
||||
typeCertificate,
|
||||
typeCertificateRequest,
|
||||
typeCertificateVerify,
|
||||
typeFinished:
|
||||
expected = protocol.EncryptionHandshake
|
||||
case typeNewSessionTicket:
|
||||
expected = protocol.Encryption1RTT
|
||||
default:
|
||||
return fmt.Errorf("unexpected handshake message: %d", msgType)
|
||||
}
|
||||
if encLevel != expected {
|
||||
return fmt.Errorf("expected handshake message %s to have encryption level %s, has %s", msgType, expected, encLevel)
|
||||
func (h *cryptoSetup) HandleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
|
||||
if err := h.handleMessage(data, encLevel); err != nil {
|
||||
return wrapError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleTransportParameters(data []byte) {
|
||||
func (h *cryptoSetup) handleMessage(data []byte, encLevel protocol.EncryptionLevel) error {
|
||||
if err := h.conn.HandleData(qtls.ToTLSEncryptionLevel(encLevel), data); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
ev := h.conn.NextEvent()
|
||||
done, err := h.handleEvent(ev)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if done {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleEvent(ev qtls.QUICEvent) (done bool, err error) {
|
||||
switch ev.Kind {
|
||||
case qtls.QUICNoEvent:
|
||||
return true, nil
|
||||
case qtls.QUICSetReadSecret:
|
||||
h.SetReadKey(ev.Level, ev.Suite, ev.Data)
|
||||
return false, nil
|
||||
case qtls.QUICSetWriteSecret:
|
||||
h.SetWriteKey(ev.Level, ev.Suite, ev.Data)
|
||||
return false, nil
|
||||
case qtls.QUICTransportParameters:
|
||||
return false, h.handleTransportParameters(ev.Data)
|
||||
case qtls.QUICTransportParametersRequired:
|
||||
h.conn.SetTransportParameters(h.ourParams.Marshal(h.perspective))
|
||||
return false, nil
|
||||
case qtls.QUICRejectedEarlyData:
|
||||
h.rejected0RTT()
|
||||
return false, nil
|
||||
case qtls.QUICWriteData:
|
||||
h.WriteRecord(ev.Level, ev.Data)
|
||||
return false, nil
|
||||
case qtls.QUICHandshakeDone:
|
||||
h.handshakeComplete()
|
||||
return false, nil
|
||||
default:
|
||||
return false, fmt.Errorf("unexpected event: %d", ev.Kind)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) NextEvent() Event {
|
||||
if len(h.events) == 0 {
|
||||
return Event{Kind: EventNoEvent}
|
||||
}
|
||||
ev := h.events[0]
|
||||
h.events = h.events[1:]
|
||||
return ev
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleTransportParameters(data []byte) error {
|
||||
var tp wire.TransportParameters
|
||||
if err := tp.Unmarshal(data, h.perspective.Opposite()); err != nil {
|
||||
h.runner.OnError(&qerr.TransportError{
|
||||
ErrorCode: qerr.TransportParameterError,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return err
|
||||
}
|
||||
h.peerParams = &tp
|
||||
h.runner.OnReceivedParams(h.peerParams)
|
||||
h.events = append(h.events, Event{Kind: EventReceivedTransportParameters, TransportParameters: h.peerParams})
|
||||
return nil
|
||||
}
|
||||
|
||||
// must be called after receiving the transport parameters
|
||||
@@ -447,13 +320,20 @@ func (h *cryptoSetup) marshalDataForSessionState() []byte {
|
||||
return h.peerParams.MarshalForSessionTicket(b)
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleDataFromSessionState(data []byte) {
|
||||
func (h *cryptoSetup) handleDataFromSessionState(data []byte) (allowEarlyData bool) {
|
||||
tp, err := h.handleDataFromSessionStateImpl(data)
|
||||
if err != nil {
|
||||
h.logger.Debugf("Restoring of transport parameters from session ticket failed: %s", err.Error())
|
||||
return
|
||||
}
|
||||
h.zeroRTTParameters = tp
|
||||
// The session ticket might have been saved from a connection that allowed 0-RTT,
|
||||
// and therefore contain transport parameters.
|
||||
// Only use them if 0-RTT is actually used on the new connection.
|
||||
if tp != nil && h.allow0RTT {
|
||||
h.zeroRTTParameters = tp
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handleDataFromSessionStateImpl(data []byte) (*wire.TransportParameters, error) {
|
||||
@@ -477,25 +357,54 @@ func (h *cryptoSetup) handleDataFromSessionStateImpl(data []byte) (*wire.Transpo
|
||||
return &tp, nil
|
||||
}
|
||||
|
||||
// only valid for the server
|
||||
func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
|
||||
var appData []byte
|
||||
// Save transport parameters to the session ticket if we're allowing 0-RTT.
|
||||
if h.extraConf.MaxEarlyData > 0 {
|
||||
appData = (&sessionTicket{
|
||||
Parameters: h.ourParams,
|
||||
RTT: h.rttStats.SmoothedRTT(),
|
||||
}).Marshal()
|
||||
func (h *cryptoSetup) getDataForSessionTicket() []byte {
|
||||
ticket := &sessionTicket{
|
||||
RTT: h.rttStats.SmoothedRTT(),
|
||||
}
|
||||
return h.conn.GetSessionTicket(appData)
|
||||
if h.allow0RTT {
|
||||
ticket.Parameters = h.ourParams
|
||||
}
|
||||
return ticket.Marshal()
|
||||
}
|
||||
|
||||
// accept0RTT is called for the server when receiving the client's session ticket.
|
||||
// It decides whether to accept 0-RTT.
|
||||
func (h *cryptoSetup) accept0RTT(sessionTicketData []byte) bool {
|
||||
// GetSessionTicket generates a new session ticket.
|
||||
// Due to limitations in crypto/tls, it's only possible to generate a single session ticket per connection.
|
||||
// It is only valid for the server.
|
||||
func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
|
||||
if err := qtls.SendSessionTicket(h.conn, h.allow0RTT); err != nil {
|
||||
// Session tickets might be disabled by tls.Config.SessionTicketsDisabled.
|
||||
// We can't check h.tlsConfig here, since the actual config might have been obtained from
|
||||
// the GetConfigForClient callback.
|
||||
// See https://github.com/golang/go/issues/62032.
|
||||
// Once that issue is resolved, this error assertion can be removed.
|
||||
if strings.Contains(err.Error(), "session ticket keys unavailable") {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
ev := h.conn.NextEvent()
|
||||
if ev.Kind != qtls.QUICWriteData || ev.Level != qtls.QUICEncryptionLevelApplication {
|
||||
panic("crypto/tls bug: where's my session ticket?")
|
||||
}
|
||||
ticket := ev.Data
|
||||
if ev := h.conn.NextEvent(); ev.Kind != qtls.QUICNoEvent {
|
||||
panic("crypto/tls bug: why more than one ticket?")
|
||||
}
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
// handleSessionTicket is called for the server when receiving the client's session ticket.
|
||||
// It reads parameters from the session ticket and checks whether to accept 0-RTT if the session ticket enabled 0-RTT.
|
||||
// Note that the fact that the session ticket allows 0-RTT doesn't mean that the actual TLS handshake enables 0-RTT:
|
||||
// A client may use a 0-RTT enabled session to resume a TLS session without using 0-RTT.
|
||||
func (h *cryptoSetup) handleSessionTicket(sessionTicketData []byte, using0RTT bool) bool {
|
||||
var t sessionTicket
|
||||
if err := t.Unmarshal(sessionTicketData); err != nil {
|
||||
h.logger.Debugf("Unmarshalling transport parameters from session ticket failed: %s", err.Error())
|
||||
if err := t.Unmarshal(sessionTicketData, using0RTT); err != nil {
|
||||
h.logger.Debugf("Unmarshalling session ticket failed: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
h.rttStats.SetInitialRTT(t.RTT)
|
||||
if !using0RTT {
|
||||
return false
|
||||
}
|
||||
valid := h.ourParams.ValidFor0RTT(t.Parameters)
|
||||
@@ -508,7 +417,6 @@ func (h *cryptoSetup) accept0RTT(sessionTicketData []byte) bool {
|
||||
return false
|
||||
}
|
||||
h.logger.Debugf("Accepting 0-RTT. Restoring RTT from session ticket: %s", t.RTT)
|
||||
h.rttStats.SetInitialRTT(t.RTT)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -522,64 +430,16 @@ func (h *cryptoSetup) rejected0RTT() {
|
||||
h.mutex.Unlock()
|
||||
|
||||
if had0RTTKeys {
|
||||
h.runner.DropKeys(protocol.Encryption0RTT)
|
||||
h.events = append(h.events, Event{Kind: EventDiscard0RTTKeys})
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handlePostHandshakeMessage() {
|
||||
// make sure the handshake has already completed
|
||||
<-h.handshakeDone
|
||||
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
|
||||
// h.alertChan is an unbuffered channel.
|
||||
// If an error occurs during conn.HandlePostHandshakeMessage,
|
||||
// it will be sent on this channel.
|
||||
// Read it from a go-routine so that HandlePostHandshakeMessage doesn't deadlock.
|
||||
alertChan := make(chan uint8, 1)
|
||||
go func() {
|
||||
<-h.isReadingHandshakeMessage
|
||||
select {
|
||||
case alert := <-h.alertChan:
|
||||
alertChan <- alert
|
||||
case <-done:
|
||||
}
|
||||
}()
|
||||
|
||||
if err := h.conn.HandlePostHandshakeMessage(); err != nil {
|
||||
select {
|
||||
case <-h.closeChan:
|
||||
case alert := <-alertChan:
|
||||
h.onError(alert, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReadHandshakeMessage is called by TLS.
|
||||
// It blocks until a new handshake message is available.
|
||||
func (h *cryptoSetup) ReadHandshakeMessage() ([]byte, error) {
|
||||
if !h.readFirstHandshakeMessage {
|
||||
h.readFirstHandshakeMessage = true
|
||||
} else {
|
||||
select {
|
||||
case h.isReadingHandshakeMessage <- struct{}{}:
|
||||
case <-h.closeChan:
|
||||
return nil, errors.New("error while handling the handshake message")
|
||||
}
|
||||
}
|
||||
select {
|
||||
case msg := <-h.messageChan:
|
||||
return msg, nil
|
||||
case <-h.closeChan:
|
||||
return nil, errors.New("error while handling the handshake message")
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) SetReadKey(encLevel qtls.EncryptionLevel, suite *qtls.CipherSuiteTLS13, trafficSecret []byte) {
|
||||
func (h *cryptoSetup) SetReadKey(el qtls.QUICEncryptionLevel, suiteID uint16, trafficSecret []byte) {
|
||||
suite := getCipherSuite(suiteID)
|
||||
h.mutex.Lock()
|
||||
switch encLevel {
|
||||
case qtls.Encryption0RTT:
|
||||
//nolint:exhaustive // The TLS stack doesn't export Initial keys.
|
||||
switch el {
|
||||
case qtls.QUICEncryptionLevelEarly:
|
||||
if h.perspective == protocol.PerspectiveClient {
|
||||
panic("Received 0-RTT read key for the client")
|
||||
}
|
||||
@@ -587,27 +447,19 @@ func (h *cryptoSetup) SetReadKey(encLevel qtls.EncryptionLevel, suite *qtls.Ciph
|
||||
createAEAD(suite, trafficSecret, h.version),
|
||||
newHeaderProtector(suite, trafficSecret, true, h.version),
|
||||
)
|
||||
h.mutex.Unlock()
|
||||
h.used0RTT.Store(true)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed 0-RTT Read keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
if h.tracer != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(protocol.Encryption0RTT, h.perspective.Opposite())
|
||||
}
|
||||
return
|
||||
case qtls.EncryptionHandshake:
|
||||
h.readEncLevel = protocol.EncryptionHandshake
|
||||
h.handshakeOpener = newHandshakeOpener(
|
||||
case qtls.QUICEncryptionLevelHandshake:
|
||||
h.handshakeOpener = newLongHeaderOpener(
|
||||
createAEAD(suite, trafficSecret, h.version),
|
||||
newHeaderProtector(suite, trafficSecret, true, h.version),
|
||||
h.dropInitialKeys,
|
||||
h.perspective,
|
||||
)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed Handshake Read keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
case qtls.EncryptionApplication:
|
||||
h.readEncLevel = protocol.Encryption1RTT
|
||||
case qtls.QUICEncryptionLevelApplication:
|
||||
h.aead.SetReadKey(suite, trafficSecret)
|
||||
h.has1RTTOpener = true
|
||||
if h.logger.Debug() {
|
||||
@@ -617,15 +469,18 @@ func (h *cryptoSetup) SetReadKey(encLevel qtls.EncryptionLevel, suite *qtls.Ciph
|
||||
panic("unexpected read encryption level")
|
||||
}
|
||||
h.mutex.Unlock()
|
||||
if h.tracer != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(h.readEncLevel, h.perspective.Opposite())
|
||||
h.events = append(h.events, Event{Kind: EventReceivedReadKeys})
|
||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(qtls.FromTLSEncryptionLevel(el), h.perspective.Opposite())
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) SetWriteKey(encLevel qtls.EncryptionLevel, suite *qtls.CipherSuiteTLS13, trafficSecret []byte) {
|
||||
func (h *cryptoSetup) SetWriteKey(el qtls.QUICEncryptionLevel, suiteID uint16, trafficSecret []byte) {
|
||||
suite := getCipherSuite(suiteID)
|
||||
h.mutex.Lock()
|
||||
switch encLevel {
|
||||
case qtls.Encryption0RTT:
|
||||
//nolint:exhaustive // The TLS stack doesn't export Initial keys.
|
||||
switch el {
|
||||
case qtls.QUICEncryptionLevelEarly:
|
||||
if h.perspective == protocol.PerspectiveServer {
|
||||
panic("Received 0-RTT write key for the server")
|
||||
}
|
||||
@@ -637,32 +492,31 @@ func (h *cryptoSetup) SetWriteKey(encLevel qtls.EncryptionLevel, suite *qtls.Cip
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed 0-RTT Write keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(protocol.Encryption0RTT, h.perspective)
|
||||
}
|
||||
// don't set used0RTT here. 0-RTT might still get rejected.
|
||||
return
|
||||
case qtls.EncryptionHandshake:
|
||||
h.writeEncLevel = protocol.EncryptionHandshake
|
||||
h.handshakeSealer = newHandshakeSealer(
|
||||
case qtls.QUICEncryptionLevelHandshake:
|
||||
h.handshakeSealer = newLongHeaderSealer(
|
||||
createAEAD(suite, trafficSecret, h.version),
|
||||
newHeaderProtector(suite, trafficSecret, true, h.version),
|
||||
h.dropInitialKeys,
|
||||
h.perspective,
|
||||
)
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed Handshake Write keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
case qtls.EncryptionApplication:
|
||||
h.writeEncLevel = protocol.Encryption1RTT
|
||||
case qtls.QUICEncryptionLevelApplication:
|
||||
h.aead.SetWriteKey(suite, trafficSecret)
|
||||
h.has1RTTSealer = true
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Installed 1-RTT Write keys (using %s)", tls.CipherSuiteName(suite.ID))
|
||||
}
|
||||
if h.zeroRTTSealer != nil {
|
||||
// Once we receive handshake keys, we know that 0-RTT was not rejected.
|
||||
h.used0RTT.Store(true)
|
||||
h.zeroRTTSealer = nil
|
||||
h.logger.Debugf("Dropping 0-RTT keys.")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.DroppedEncryptionLevel != nil {
|
||||
h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
|
||||
}
|
||||
}
|
||||
@@ -670,56 +524,40 @@ func (h *cryptoSetup) SetWriteKey(encLevel qtls.EncryptionLevel, suite *qtls.Cip
|
||||
panic("unexpected write encryption level")
|
||||
}
|
||||
h.mutex.Unlock()
|
||||
if h.tracer != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(h.writeEncLevel, h.perspective)
|
||||
if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
|
||||
h.tracer.UpdatedKeyFromTLS(qtls.FromTLSEncryptionLevel(el), h.perspective)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteRecord is called when TLS writes data
|
||||
func (h *cryptoSetup) WriteRecord(p []byte) (int, error) {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
//nolint:exhaustive // LS records can only be written for Initial and Handshake.
|
||||
switch h.writeEncLevel {
|
||||
case protocol.EncryptionInitial:
|
||||
// assume that the first WriteRecord call contains the ClientHello
|
||||
n, err := h.initialStream.Write(p)
|
||||
if !h.clientHelloWritten && h.perspective == protocol.PerspectiveClient {
|
||||
h.clientHelloWritten = true
|
||||
close(h.clientHelloWrittenChan)
|
||||
if h.zeroRTTSealer != nil && h.zeroRTTParameters != nil {
|
||||
h.logger.Debugf("Doing 0-RTT.")
|
||||
h.zeroRTTParametersChan <- h.zeroRTTParameters
|
||||
} else {
|
||||
h.logger.Debugf("Not doing 0-RTT.")
|
||||
h.zeroRTTParametersChan <- nil
|
||||
}
|
||||
}
|
||||
return n, err
|
||||
case protocol.EncryptionHandshake:
|
||||
return h.handshakeStream.Write(p)
|
||||
func (h *cryptoSetup) WriteRecord(encLevel qtls.QUICEncryptionLevel, p []byte) {
|
||||
//nolint:exhaustive // handshake records can only be written for Initial and Handshake.
|
||||
switch encLevel {
|
||||
case qtls.QUICEncryptionLevelInitial:
|
||||
h.events = append(h.events, Event{Kind: EventWriteInitialData, Data: p})
|
||||
case qtls.QUICEncryptionLevelHandshake:
|
||||
h.events = append(h.events, Event{Kind: EventWriteHandshakeData, Data: p})
|
||||
case qtls.QUICEncryptionLevelApplication:
|
||||
panic("unexpected write")
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected write encryption level: %s", h.writeEncLevel))
|
||||
panic(fmt.Sprintf("unexpected write encryption level: %s", encLevel))
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) SendAlert(alert uint8) {
|
||||
select {
|
||||
case h.alertChan <- alert:
|
||||
case <-h.closeChan:
|
||||
// no need to send an alert when we've already closed
|
||||
}
|
||||
}
|
||||
|
||||
// used a callback in the handshakeSealer and handshakeOpener
|
||||
func (h *cryptoSetup) dropInitialKeys() {
|
||||
func (h *cryptoSetup) DiscardInitialKeys() {
|
||||
h.mutex.Lock()
|
||||
dropped := h.initialOpener != nil
|
||||
h.initialOpener = nil
|
||||
h.initialSealer = nil
|
||||
h.mutex.Unlock()
|
||||
h.runner.DropKeys(protocol.EncryptionInitial)
|
||||
h.logger.Debugf("Dropping Initial keys.")
|
||||
if dropped {
|
||||
h.logger.Debugf("Dropping Initial keys.")
|
||||
}
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) handshakeComplete() {
|
||||
h.handshakeCompleteTime = time.Now()
|
||||
h.events = append(h.events, Event{Kind: EventHandshakeComplete})
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) SetHandshakeConfirmed() {
|
||||
@@ -734,7 +572,6 @@ func (h *cryptoSetup) SetHandshakeConfirmed() {
|
||||
}
|
||||
h.mutex.Unlock()
|
||||
if dropped {
|
||||
h.runner.DropKeys(protocol.EncryptionHandshake)
|
||||
h.logger.Debugf("Dropping Handshake keys.")
|
||||
}
|
||||
}
|
||||
@@ -827,7 +664,7 @@ func (h *cryptoSetup) Get1RTTOpener() (ShortHeaderOpener, error) {
|
||||
if h.zeroRTTOpener != nil && time.Since(h.handshakeCompleteTime) > 3*h.rttStats.PTO(true) {
|
||||
h.zeroRTTOpener = nil
|
||||
h.logger.Debugf("Dropping 0-RTT keys.")
|
||||
if h.tracer != nil {
|
||||
if h.tracer != nil && h.tracer.DroppedEncryptionLevel != nil {
|
||||
h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
|
||||
}
|
||||
}
|
||||
@@ -839,5 +676,16 @@ func (h *cryptoSetup) Get1RTTOpener() (ShortHeaderOpener, error) {
|
||||
}
|
||||
|
||||
func (h *cryptoSetup) ConnectionState() ConnectionState {
|
||||
return qtls.GetConnectionState(h.conn)
|
||||
return ConnectionState{
|
||||
ConnectionState: h.conn.ConnectionState(),
|
||||
Used0RTT: h.used0RTT.Load(),
|
||||
}
|
||||
}
|
||||
|
||||
func wrapError(err error) error {
|
||||
// alert 80 is an internal error
|
||||
if alertErr := qtls.AlertError(0); errors.As(err, &alertErr) && alertErr != 80 {
|
||||
return qerr.NewLocalCryptoError(uint8(alertErr), err)
|
||||
}
|
||||
return &qerr.TransportError{ErrorCode: qerr.InternalError, ErrorMessage: err.Error()}
|
||||
}
|
||||
|
||||
7
vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
generated
vendored
7
vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
generated
vendored
@@ -10,7 +10,6 @@ import (
|
||||
"golang.org/x/crypto/chacha20"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
)
|
||||
|
||||
type headerProtector interface {
|
||||
@@ -25,7 +24,7 @@ func hkdfHeaderProtectionLabel(v protocol.VersionNumber) string {
|
||||
return "quic hp"
|
||||
}
|
||||
|
||||
func newHeaderProtector(suite *qtls.CipherSuiteTLS13, trafficSecret []byte, isLongHeader bool, v protocol.VersionNumber) headerProtector {
|
||||
func newHeaderProtector(suite *cipherSuite, trafficSecret []byte, isLongHeader bool, v protocol.VersionNumber) headerProtector {
|
||||
hkdfLabel := hkdfHeaderProtectionLabel(v)
|
||||
switch suite.ID {
|
||||
case tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384:
|
||||
@@ -45,7 +44,7 @@ type aesHeaderProtector struct {
|
||||
|
||||
var _ headerProtector = &aesHeaderProtector{}
|
||||
|
||||
func newAESHeaderProtector(suite *qtls.CipherSuiteTLS13, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
|
||||
func newAESHeaderProtector(suite *cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
|
||||
hpKey := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, hkdfLabel, suite.KeyLen)
|
||||
block, err := aes.NewCipher(hpKey)
|
||||
if err != nil {
|
||||
@@ -90,7 +89,7 @@ type chachaHeaderProtector struct {
|
||||
|
||||
var _ headerProtector = &chachaHeaderProtector{}
|
||||
|
||||
func newChaChaHeaderProtector(suite *qtls.CipherSuiteTLS13, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
|
||||
func newChaChaHeaderProtector(suite *cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
|
||||
hpKey := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, hkdfLabel, suite.KeyLen)
|
||||
|
||||
p := &chachaHeaderProtector{
|
||||
|
||||
22
vendor/github.com/quic-go/quic-go/internal/handshake/initial_aead.go
generated
vendored
22
vendor/github.com/quic-go/quic-go/internal/handshake/initial_aead.go
generated
vendored
@@ -7,13 +7,11 @@ import (
|
||||
"golang.org/x/crypto/hkdf"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
)
|
||||
|
||||
var (
|
||||
quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}
|
||||
quicSaltV1 = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}
|
||||
quicSaltV2 = []byte{0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9}
|
||||
quicSaltV1 = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}
|
||||
quicSaltV2 = []byte{0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9}
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -27,18 +25,10 @@ func getSalt(v protocol.VersionNumber) []byte {
|
||||
if v == protocol.Version2 {
|
||||
return quicSaltV2
|
||||
}
|
||||
if v == protocol.Version1 {
|
||||
return quicSaltV1
|
||||
}
|
||||
return quicSaltOld
|
||||
return quicSaltV1
|
||||
}
|
||||
|
||||
var initialSuite = &qtls.CipherSuiteTLS13{
|
||||
ID: tls.TLS_AES_128_GCM_SHA256,
|
||||
KeyLen: 16,
|
||||
AEAD: qtls.AEADAESGCMTLS13,
|
||||
Hash: crypto.SHA256,
|
||||
}
|
||||
var initialSuite = getCipherSuite(tls.TLS_AES_128_GCM_SHA256)
|
||||
|
||||
// NewInitialAEAD creates a new AEAD for Initial encryption / decryption.
|
||||
func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective, v protocol.VersionNumber) (LongHeaderSealer, LongHeaderOpener) {
|
||||
@@ -54,8 +44,8 @@ func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective, v p
|
||||
myKey, myIV := computeInitialKeyAndIV(mySecret, v)
|
||||
otherKey, otherIV := computeInitialKeyAndIV(otherSecret, v)
|
||||
|
||||
encrypter := qtls.AEADAESGCMTLS13(myKey, myIV)
|
||||
decrypter := qtls.AEADAESGCMTLS13(otherKey, otherIV)
|
||||
encrypter := initialSuite.AEAD(myKey, myIV)
|
||||
decrypter := initialSuite.AEAD(otherKey, otherIV)
|
||||
|
||||
return newLongHeaderSealer(encrypter, newHeaderProtector(initialSuite, mySecret, true, v)),
|
||||
newLongHeaderOpener(decrypter, newAESHeaderProtector(initialSuite, otherSecret, true, hkdfHeaderProtectionLabel(v)))
|
||||
|
||||
54
vendor/github.com/quic-go/quic-go/internal/handshake/interface.go
generated
vendored
54
vendor/github.com/quic-go/quic-go/internal/handshake/interface.go
generated
vendored
@@ -1,12 +1,12 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
)
|
||||
|
||||
@@ -22,9 +22,6 @@ var (
|
||||
ErrDecryptionFailed = errors.New("decryption failed")
|
||||
)
|
||||
|
||||
// ConnectionState contains information about the state of the connection.
|
||||
type ConnectionState = qtls.ConnectionState
|
||||
|
||||
type headerDecryptor interface {
|
||||
DecryptHeader(sample []byte, firstByte *byte, pnBytes []byte)
|
||||
}
|
||||
@@ -56,29 +53,54 @@ type ShortHeaderSealer interface {
|
||||
KeyPhase() protocol.KeyPhaseBit
|
||||
}
|
||||
|
||||
// A tlsExtensionHandler sends and received the QUIC TLS extension.
|
||||
type tlsExtensionHandler interface {
|
||||
GetExtensions(msgType uint8) []qtls.Extension
|
||||
ReceivedExtensions(msgType uint8, exts []qtls.Extension)
|
||||
TransportParameters() <-chan []byte
|
||||
type ConnectionState struct {
|
||||
tls.ConnectionState
|
||||
Used0RTT bool
|
||||
}
|
||||
|
||||
type handshakeRunner interface {
|
||||
OnReceivedParams(*wire.TransportParameters)
|
||||
OnHandshakeComplete()
|
||||
OnError(error)
|
||||
DropKeys(protocol.EncryptionLevel)
|
||||
// EventKind is the kind of handshake event.
|
||||
type EventKind uint8
|
||||
|
||||
const (
|
||||
// EventNoEvent signals that there are no new handshake events
|
||||
EventNoEvent EventKind = iota + 1
|
||||
// EventWriteInitialData contains new CRYPTO data to send at the Initial encryption level
|
||||
EventWriteInitialData
|
||||
// EventWriteHandshakeData contains new CRYPTO data to send at the Handshake encryption level
|
||||
EventWriteHandshakeData
|
||||
// EventReceivedReadKeys signals that new decryption keys are available.
|
||||
// It doesn't say which encryption level those keys are for.
|
||||
EventReceivedReadKeys
|
||||
// EventDiscard0RTTKeys signals that the Handshake keys were discarded.
|
||||
EventDiscard0RTTKeys
|
||||
// EventReceivedTransportParameters contains the transport parameters sent by the peer.
|
||||
EventReceivedTransportParameters
|
||||
// EventRestoredTransportParameters contains the transport parameters restored from the session ticket.
|
||||
// It is only used for the client.
|
||||
EventRestoredTransportParameters
|
||||
// EventHandshakeComplete signals that the TLS handshake was completed.
|
||||
EventHandshakeComplete
|
||||
)
|
||||
|
||||
// Event is a handshake event.
|
||||
type Event struct {
|
||||
Kind EventKind
|
||||
Data []byte
|
||||
TransportParameters *wire.TransportParameters
|
||||
}
|
||||
|
||||
// CryptoSetup handles the handshake and protecting / unprotecting packets
|
||||
type CryptoSetup interface {
|
||||
RunHandshake()
|
||||
StartHandshake() error
|
||||
io.Closer
|
||||
ChangeConnectionID(protocol.ConnectionID)
|
||||
GetSessionTicket() ([]byte, error)
|
||||
|
||||
HandleMessage([]byte, protocol.EncryptionLevel) bool
|
||||
HandleMessage([]byte, protocol.EncryptionLevel) error
|
||||
NextEvent() Event
|
||||
|
||||
SetLargest1RTTAcked(protocol.PacketNumber) error
|
||||
DiscardInitialKeys()
|
||||
SetHandshakeConfirmed()
|
||||
ConnectionState() ConnectionState
|
||||
|
||||
|
||||
6
vendor/github.com/quic-go/quic-go/internal/handshake/mockgen.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/handshake/mockgen.go
generated
vendored
@@ -1,6 +0,0 @@
|
||||
//go:build gomock || generate
|
||||
|
||||
package handshake
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package handshake -destination mock_handshake_runner_test.go github.com/quic-go/quic-go/internal/handshake HandshakeRunner"
|
||||
type HandshakeRunner = handshakeRunner
|
||||
25
vendor/github.com/quic-go/quic-go/internal/handshake/retry.go
generated
vendored
25
vendor/github.com/quic-go/quic-go/internal/handshake/retry.go
generated
vendored
@@ -11,13 +11,11 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
retryAEADdraft29 cipher.AEAD // used for QUIC draft versions up to 34
|
||||
retryAEADv1 cipher.AEAD // used for QUIC v1 (RFC 9000)
|
||||
retryAEADv2 cipher.AEAD // used for QUIC v2
|
||||
retryAEADv1 cipher.AEAD // used for QUIC v1 (RFC 9000)
|
||||
retryAEADv2 cipher.AEAD // used for QUIC v2 (RFC 9369)
|
||||
)
|
||||
|
||||
func init() {
|
||||
retryAEADdraft29 = initAEAD([16]byte{0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, 0xe1})
|
||||
retryAEADv1 = initAEAD([16]byte{0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e})
|
||||
retryAEADv2 = initAEAD([16]byte{0x8f, 0xb4, 0xb0, 0x1b, 0x56, 0xac, 0x48, 0xe2, 0x60, 0xfb, 0xcb, 0xce, 0xad, 0x7c, 0xcc, 0x92})
|
||||
}
|
||||
@@ -35,11 +33,10 @@ func initAEAD(key [16]byte) cipher.AEAD {
|
||||
}
|
||||
|
||||
var (
|
||||
retryBuf bytes.Buffer
|
||||
retryMutex sync.Mutex
|
||||
retryNonceDraft29 = [12]byte{0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c}
|
||||
retryNonceV1 = [12]byte{0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}
|
||||
retryNonceV2 = [12]byte{0xd8, 0x69, 0x69, 0xbc, 0x2d, 0x7c, 0x6d, 0x99, 0x90, 0xef, 0xb0, 0x4a}
|
||||
retryBuf bytes.Buffer
|
||||
retryMutex sync.Mutex
|
||||
retryNonceV1 = [12]byte{0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}
|
||||
retryNonceV2 = [12]byte{0xd8, 0x69, 0x69, 0xbc, 0x2d, 0x7c, 0x6d, 0x99, 0x90, 0xef, 0xb0, 0x4a}
|
||||
)
|
||||
|
||||
// GetRetryIntegrityTag calculates the integrity tag on a Retry packet
|
||||
@@ -54,14 +51,10 @@ func GetRetryIntegrityTag(retry []byte, origDestConnID protocol.ConnectionID, ve
|
||||
|
||||
var tag [16]byte
|
||||
var sealed []byte
|
||||
//nolint:exhaustive // These are all the versions we support
|
||||
switch version {
|
||||
case protocol.Version1:
|
||||
sealed = retryAEADv1.Seal(tag[:0], retryNonceV1[:], nil, retryBuf.Bytes())
|
||||
case protocol.Version2:
|
||||
if version == protocol.Version2 {
|
||||
sealed = retryAEADv2.Seal(tag[:0], retryNonceV2[:], nil, retryBuf.Bytes())
|
||||
default:
|
||||
sealed = retryAEADdraft29.Seal(tag[:0], retryNonceDraft29[:], nil, retryBuf.Bytes())
|
||||
} else {
|
||||
sealed = retryAEADv1.Seal(tag[:0], retryNonceV1[:], nil, retryBuf.Bytes())
|
||||
}
|
||||
if len(sealed) != 16 {
|
||||
panic(fmt.Sprintf("unexpected Retry integrity tag length: %d", len(sealed)))
|
||||
|
||||
19
vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go
generated
vendored
19
vendor/github.com/quic-go/quic-go/internal/handshake/session_ticket.go
generated
vendored
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
)
|
||||
|
||||
const sessionTicketRevision = 2
|
||||
const sessionTicketRevision = 4
|
||||
|
||||
type sessionTicket struct {
|
||||
Parameters *wire.TransportParameters
|
||||
@@ -21,10 +21,13 @@ func (t *sessionTicket) Marshal() []byte {
|
||||
b := make([]byte, 0, 256)
|
||||
b = quicvarint.Append(b, sessionTicketRevision)
|
||||
b = quicvarint.Append(b, uint64(t.RTT.Microseconds()))
|
||||
if t.Parameters == nil {
|
||||
return b
|
||||
}
|
||||
return t.Parameters.MarshalForSessionTicket(b)
|
||||
}
|
||||
|
||||
func (t *sessionTicket) Unmarshal(b []byte) error {
|
||||
func (t *sessionTicket) Unmarshal(b []byte, using0RTT bool) error {
|
||||
r := bytes.NewReader(b)
|
||||
rev, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
@@ -37,11 +40,15 @@ func (t *sessionTicket) Unmarshal(b []byte) error {
|
||||
if err != nil {
|
||||
return errors.New("failed to read RTT")
|
||||
}
|
||||
var tp wire.TransportParameters
|
||||
if err := tp.UnmarshalFromSessionTicket(r); err != nil {
|
||||
return fmt.Errorf("unmarshaling transport parameters from session ticket failed: %s", err.Error())
|
||||
if using0RTT {
|
||||
var tp wire.TransportParameters
|
||||
if err := tp.UnmarshalFromSessionTicket(r); err != nil {
|
||||
return fmt.Errorf("unmarshaling transport parameters from session ticket failed: %s", err.Error())
|
||||
}
|
||||
t.Parameters = &tp
|
||||
} else if r.Len() > 0 {
|
||||
return fmt.Errorf("the session ticket has more bytes than expected")
|
||||
}
|
||||
t.Parameters = &tp
|
||||
t.RTT = time.Duration(rtt) * time.Microsecond
|
||||
return nil
|
||||
}
|
||||
|
||||
68
vendor/github.com/quic-go/quic-go/internal/handshake/tls_extension_handler.go
generated
vendored
68
vendor/github.com/quic-go/quic-go/internal/handshake/tls_extension_handler.go
generated
vendored
@@ -1,68 +0,0 @@
|
||||
package handshake
|
||||
|
||||
import (
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
)
|
||||
|
||||
const (
|
||||
quicTLSExtensionTypeOldDrafts = 0xffa5
|
||||
quicTLSExtensionType = 0x39
|
||||
)
|
||||
|
||||
type extensionHandler struct {
|
||||
ourParams []byte
|
||||
paramsChan chan []byte
|
||||
|
||||
extensionType uint16
|
||||
|
||||
perspective protocol.Perspective
|
||||
}
|
||||
|
||||
var _ tlsExtensionHandler = &extensionHandler{}
|
||||
|
||||
// newExtensionHandler creates a new extension handler
|
||||
func newExtensionHandler(params []byte, pers protocol.Perspective, v protocol.VersionNumber) tlsExtensionHandler {
|
||||
et := uint16(quicTLSExtensionType)
|
||||
if v == protocol.VersionDraft29 {
|
||||
et = quicTLSExtensionTypeOldDrafts
|
||||
}
|
||||
return &extensionHandler{
|
||||
ourParams: params,
|
||||
paramsChan: make(chan []byte),
|
||||
perspective: pers,
|
||||
extensionType: et,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *extensionHandler) GetExtensions(msgType uint8) []qtls.Extension {
|
||||
if (h.perspective == protocol.PerspectiveClient && messageType(msgType) != typeClientHello) ||
|
||||
(h.perspective == protocol.PerspectiveServer && messageType(msgType) != typeEncryptedExtensions) {
|
||||
return nil
|
||||
}
|
||||
return []qtls.Extension{{
|
||||
Type: h.extensionType,
|
||||
Data: h.ourParams,
|
||||
}}
|
||||
}
|
||||
|
||||
func (h *extensionHandler) ReceivedExtensions(msgType uint8, exts []qtls.Extension) {
|
||||
if (h.perspective == protocol.PerspectiveClient && messageType(msgType) != typeEncryptedExtensions) ||
|
||||
(h.perspective == protocol.PerspectiveServer && messageType(msgType) != typeClientHello) {
|
||||
return
|
||||
}
|
||||
|
||||
var data []byte
|
||||
for _, ext := range exts {
|
||||
if ext.Type == h.extensionType {
|
||||
data = ext.Data
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
h.paramsChan <- data
|
||||
}
|
||||
|
||||
func (h *extensionHandler) TransportParameters() <-chan []byte {
|
||||
return h.paramsChan
|
||||
}
|
||||
13
vendor/github.com/quic-go/quic-go/internal/handshake/token_generator.go
generated
vendored
13
vendor/github.com/quic-go/quic-go/internal/handshake/token_generator.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
@@ -45,15 +44,9 @@ type TokenGenerator struct {
|
||||
tokenProtector tokenProtector
|
||||
}
|
||||
|
||||
// NewTokenGenerator initializes a new TookenGenerator
|
||||
func NewTokenGenerator(rand io.Reader) (*TokenGenerator, error) {
|
||||
tokenProtector, err := newTokenProtector(rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &TokenGenerator{
|
||||
tokenProtector: tokenProtector,
|
||||
}, nil
|
||||
// NewTokenGenerator initializes a new TokenGenerator
|
||||
func NewTokenGenerator(key TokenProtectorKey) *TokenGenerator {
|
||||
return &TokenGenerator{tokenProtector: newTokenProtector(key)}
|
||||
}
|
||||
|
||||
// NewRetryToken generates a new token for a Retry for a given source address
|
||||
|
||||
33
vendor/github.com/quic-go/quic-go/internal/handshake/token_protector.go
generated
vendored
33
vendor/github.com/quic-go/quic-go/internal/handshake/token_protector.go
generated
vendored
@@ -3,6 +3,7 @@ package handshake
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -10,6 +11,9 @@ import (
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
|
||||
// TokenProtectorKey is the key used to encrypt both Retry and session resumption tokens.
|
||||
type TokenProtectorKey [32]byte
|
||||
|
||||
// TokenProtector is used to create and verify a token
|
||||
type tokenProtector interface {
|
||||
// NewToken creates a new token
|
||||
@@ -18,40 +22,29 @@ type tokenProtector interface {
|
||||
DecodeToken([]byte) ([]byte, error)
|
||||
}
|
||||
|
||||
const (
|
||||
tokenSecretSize = 32
|
||||
tokenNonceSize = 32
|
||||
)
|
||||
const tokenNonceSize = 32
|
||||
|
||||
// tokenProtector is used to create and verify a token
|
||||
type tokenProtectorImpl struct {
|
||||
rand io.Reader
|
||||
secret []byte
|
||||
key TokenProtectorKey
|
||||
}
|
||||
|
||||
// newTokenProtector creates a source for source address tokens
|
||||
func newTokenProtector(rand io.Reader) (tokenProtector, error) {
|
||||
secret := make([]byte, tokenSecretSize)
|
||||
if _, err := rand.Read(secret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tokenProtectorImpl{
|
||||
rand: rand,
|
||||
secret: secret,
|
||||
}, nil
|
||||
func newTokenProtector(key TokenProtectorKey) tokenProtector {
|
||||
return &tokenProtectorImpl{key: key}
|
||||
}
|
||||
|
||||
// NewToken encodes data into a new token.
|
||||
func (s *tokenProtectorImpl) NewToken(data []byte) ([]byte, error) {
|
||||
nonce := make([]byte, tokenNonceSize)
|
||||
if _, err := s.rand.Read(nonce); err != nil {
|
||||
var nonce [tokenNonceSize]byte
|
||||
if _, err := rand.Read(nonce[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aead, aeadNonce, err := s.createAEAD(nonce)
|
||||
aead, aeadNonce, err := s.createAEAD(nonce[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append(nonce, aead.Seal(nil, aeadNonce, data, nil)...), nil
|
||||
return append(nonce[:], aead.Seal(nil, aeadNonce, data, nil)...), nil
|
||||
}
|
||||
|
||||
// DecodeToken decodes a token.
|
||||
@@ -68,7 +61,7 @@ func (s *tokenProtectorImpl) DecodeToken(p []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (s *tokenProtectorImpl) createAEAD(nonce []byte) (cipher.AEAD, []byte, error) {
|
||||
h := hkdf.New(sha256.New, s.secret, nonce, []byte("quic-go token source"))
|
||||
h := hkdf.New(sha256.New, s.key[:], nonce, []byte("quic-go token source"))
|
||||
key := make([]byte, 32) // use a 32 byte key, in order to select AES-256
|
||||
if _, err := io.ReadFull(h, key); err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
21
vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
generated
vendored
21
vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
generated
vendored
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/qerr"
|
||||
"github.com/quic-go/quic-go/internal/qtls"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
)
|
||||
@@ -24,7 +23,7 @@ var KeyUpdateInterval uint64 = protocol.KeyUpdateInterval
|
||||
var FirstKeyUpdateInterval uint64 = 100
|
||||
|
||||
type updatableAEAD struct {
|
||||
suite *qtls.CipherSuiteTLS13
|
||||
suite *cipherSuite
|
||||
|
||||
keyPhase protocol.KeyPhase
|
||||
largestAcked protocol.PacketNumber
|
||||
@@ -58,7 +57,7 @@ type updatableAEAD struct {
|
||||
|
||||
rttStats *utils.RTTStats
|
||||
|
||||
tracer logging.ConnectionTracer
|
||||
tracer *logging.ConnectionTracer
|
||||
logger utils.Logger
|
||||
version protocol.VersionNumber
|
||||
|
||||
@@ -71,7 +70,7 @@ var (
|
||||
_ ShortHeaderSealer = &updatableAEAD{}
|
||||
)
|
||||
|
||||
func newUpdatableAEAD(rttStats *utils.RTTStats, tracer logging.ConnectionTracer, logger utils.Logger, version protocol.VersionNumber) *updatableAEAD {
|
||||
func newUpdatableAEAD(rttStats *utils.RTTStats, tracer *logging.ConnectionTracer, logger utils.Logger, version protocol.VersionNumber) *updatableAEAD {
|
||||
return &updatableAEAD{
|
||||
firstPacketNumber: protocol.InvalidPacketNumber,
|
||||
largestAcked: protocol.InvalidPacketNumber,
|
||||
@@ -87,7 +86,7 @@ func newUpdatableAEAD(rttStats *utils.RTTStats, tracer logging.ConnectionTracer,
|
||||
func (a *updatableAEAD) rollKeys() {
|
||||
if a.prevRcvAEAD != nil {
|
||||
a.logger.Debugf("Dropping key phase %d ahead of scheduled time. Drop time was: %s", a.keyPhase-1, a.prevRcvAEADExpiry)
|
||||
if a.tracer != nil {
|
||||
if a.tracer != nil && a.tracer.DroppedKey != nil {
|
||||
a.tracer.DroppedKey(a.keyPhase - 1)
|
||||
}
|
||||
a.prevRcvAEADExpiry = time.Time{}
|
||||
@@ -121,7 +120,7 @@ func (a *updatableAEAD) getNextTrafficSecret(hash crypto.Hash, ts []byte) []byte
|
||||
// SetReadKey sets the read key.
|
||||
// For the client, this function is called before SetWriteKey.
|
||||
// For the server, this function is called after SetWriteKey.
|
||||
func (a *updatableAEAD) SetReadKey(suite *qtls.CipherSuiteTLS13, trafficSecret []byte) {
|
||||
func (a *updatableAEAD) SetReadKey(suite *cipherSuite, trafficSecret []byte) {
|
||||
a.rcvAEAD = createAEAD(suite, trafficSecret, a.version)
|
||||
a.headerDecrypter = newHeaderProtector(suite, trafficSecret, false, a.version)
|
||||
if a.suite == nil {
|
||||
@@ -135,7 +134,7 @@ func (a *updatableAEAD) SetReadKey(suite *qtls.CipherSuiteTLS13, trafficSecret [
|
||||
// SetWriteKey sets the write key.
|
||||
// For the client, this function is called after SetReadKey.
|
||||
// For the server, this function is called before SetWriteKey.
|
||||
func (a *updatableAEAD) SetWriteKey(suite *qtls.CipherSuiteTLS13, trafficSecret []byte) {
|
||||
func (a *updatableAEAD) SetWriteKey(suite *cipherSuite, trafficSecret []byte) {
|
||||
a.sendAEAD = createAEAD(suite, trafficSecret, a.version)
|
||||
a.headerEncrypter = newHeaderProtector(suite, trafficSecret, false, a.version)
|
||||
if a.suite == nil {
|
||||
@@ -146,7 +145,7 @@ func (a *updatableAEAD) SetWriteKey(suite *qtls.CipherSuiteTLS13, trafficSecret
|
||||
a.nextSendAEAD = createAEAD(suite, a.nextSendTrafficSecret, a.version)
|
||||
}
|
||||
|
||||
func (a *updatableAEAD) setAEADParameters(aead cipher.AEAD, suite *qtls.CipherSuiteTLS13) {
|
||||
func (a *updatableAEAD) setAEADParameters(aead cipher.AEAD, suite *cipherSuite) {
|
||||
a.nonceBuf = make([]byte, aead.NonceSize())
|
||||
a.aeadOverhead = aead.Overhead()
|
||||
a.suite = suite
|
||||
@@ -183,7 +182,7 @@ func (a *updatableAEAD) open(dst, src []byte, rcvTime time.Time, pn protocol.Pac
|
||||
a.prevRcvAEAD = nil
|
||||
a.logger.Debugf("Dropping key phase %d", a.keyPhase-1)
|
||||
a.prevRcvAEADExpiry = time.Time{}
|
||||
if a.tracer != nil {
|
||||
if a.tracer != nil && a.tracer.DroppedKey != nil {
|
||||
a.tracer.DroppedKey(a.keyPhase - 1)
|
||||
}
|
||||
}
|
||||
@@ -217,7 +216,7 @@ func (a *updatableAEAD) open(dst, src []byte, rcvTime time.Time, pn protocol.Pac
|
||||
// The peer initiated this key update. It's safe to drop the keys for the previous generation now.
|
||||
// Start a timer to drop the previous key generation.
|
||||
a.startKeyDropTimer(rcvTime)
|
||||
if a.tracer != nil {
|
||||
if a.tracer != nil && a.tracer.UpdatedKey != nil {
|
||||
a.tracer.UpdatedKey(a.keyPhase, true)
|
||||
}
|
||||
a.firstRcvdWithCurrentKey = pn
|
||||
@@ -309,7 +308,7 @@ func (a *updatableAEAD) KeyPhase() protocol.KeyPhaseBit {
|
||||
if a.shouldInitiateKeyUpdate() {
|
||||
a.rollKeys()
|
||||
a.logger.Debugf("Initiating key update to key phase %d", a.keyPhase)
|
||||
if a.tracer != nil {
|
||||
if a.tracer != nil && a.tracer.UpdatedKey != nil {
|
||||
a.tracer.UpdatedKey(a.keyPhase, false)
|
||||
}
|
||||
}
|
||||
|
||||
13
vendor/github.com/quic-go/quic-go/internal/protocol/params.go
generated
vendored
13
vendor/github.com/quic-go/quic-go/internal/protocol/params.go
generated
vendored
@@ -5,6 +5,9 @@ import "time"
|
||||
// DesiredReceiveBufferSize is the kernel UDP receive buffer size that we'd like to use.
|
||||
const DesiredReceiveBufferSize = (1 << 20) * 2 // 2 MB
|
||||
|
||||
// DesiredSendBufferSize is the kernel UDP send buffer size that we'd like to use.
|
||||
const DesiredSendBufferSize = (1 << 20) * 2 // 2 MB
|
||||
|
||||
// InitialPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
|
||||
const InitialPacketSizeIPv4 = 1252
|
||||
|
||||
@@ -62,9 +65,6 @@ const MaxAcceptQueueSize = 32
|
||||
// TokenValidity is the duration that a (non-retry) token is considered valid
|
||||
const TokenValidity = 24 * time.Hour
|
||||
|
||||
// RetryTokenValidity is the duration that a retry token is considered valid
|
||||
const RetryTokenValidity = 10 * time.Second
|
||||
|
||||
// MaxOutstandingSentPackets is maximum number of packets saved for retransmission.
|
||||
// When reached, it imposes a soft limit on sending new packets:
|
||||
// Sending ACKs and retransmission is still allowed, but now new regular packets can be sent.
|
||||
@@ -105,9 +105,6 @@ const DefaultIdleTimeout = 30 * time.Second
|
||||
// DefaultHandshakeIdleTimeout is the default idle timeout used before handshake completion.
|
||||
const DefaultHandshakeIdleTimeout = 5 * time.Second
|
||||
|
||||
// DefaultHandshakeTimeout is the default timeout for a connection until the crypto handshake succeeds.
|
||||
const DefaultHandshakeTimeout = 10 * time.Second
|
||||
|
||||
// MaxKeepAliveInterval is the maximum time until we send a packet to keep a connection alive.
|
||||
// It should be shorter than the time that NATs clear their mapping.
|
||||
const MaxKeepAliveInterval = 20 * time.Second
|
||||
@@ -132,10 +129,6 @@ const MaxPostHandshakeCryptoFrameSize = 1000
|
||||
// but must ensure that a maximum size ACK frame fits into one packet.
|
||||
const MaxAckFrameSize ByteCount = 1000
|
||||
|
||||
// DefaultMaxDatagramFrameSize is the maximum size of a DATAGRAM frame (RFC 9221).
|
||||
// The size is chosen such that a DATAGRAM frame fits into a QUIC packet.
|
||||
const DefaultMaxDatagramFrameSize ByteCount = 1200
|
||||
|
||||
// DatagramRcvQueueLen is the length of the receive queue for DATAGRAM frames (RFC 9221)
|
||||
const DatagramRcvQueueLen = 128
|
||||
|
||||
|
||||
65
vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go
generated
vendored
65
vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go
generated
vendored
@@ -37,12 +37,61 @@ func (t PacketType) String() string {
|
||||
type ECN uint8
|
||||
|
||||
const (
|
||||
ECNNon ECN = iota // 00
|
||||
ECT1 // 01
|
||||
ECT0 // 10
|
||||
ECNCE // 11
|
||||
ECNUnsupported ECN = iota
|
||||
ECNNon // 00
|
||||
ECT1 // 01
|
||||
ECT0 // 10
|
||||
ECNCE // 11
|
||||
)
|
||||
|
||||
func ParseECNHeaderBits(bits byte) ECN {
|
||||
switch bits {
|
||||
case 0:
|
||||
return ECNNon
|
||||
case 0b00000010:
|
||||
return ECT0
|
||||
case 0b00000001:
|
||||
return ECT1
|
||||
case 0b00000011:
|
||||
return ECNCE
|
||||
default:
|
||||
panic("invalid ECN bits")
|
||||
}
|
||||
}
|
||||
|
||||
func (e ECN) ToHeaderBits() byte {
|
||||
//nolint:exhaustive // There are only 4 values.
|
||||
switch e {
|
||||
case ECNNon:
|
||||
return 0
|
||||
case ECT0:
|
||||
return 0b00000010
|
||||
case ECT1:
|
||||
return 0b00000001
|
||||
case ECNCE:
|
||||
return 0b00000011
|
||||
default:
|
||||
panic("ECN unsupported")
|
||||
}
|
||||
}
|
||||
|
||||
func (e ECN) String() string {
|
||||
switch e {
|
||||
case ECNUnsupported:
|
||||
return "ECN unsupported"
|
||||
case ECNNon:
|
||||
return "Not-ECT"
|
||||
case ECT1:
|
||||
return "ECT(1)"
|
||||
case ECT0:
|
||||
return "ECT(0)"
|
||||
case ECNCE:
|
||||
return "CE"
|
||||
default:
|
||||
return fmt.Sprintf("invalid ECN value: %d", e)
|
||||
}
|
||||
}
|
||||
|
||||
// A ByteCount in QUIC
|
||||
type ByteCount int64
|
||||
|
||||
@@ -59,7 +108,10 @@ type StatelessResetToken [16]byte
|
||||
// ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header,
|
||||
// UDP adds an additional 8 bytes. This is a total overhead of 48 bytes.
|
||||
// Ethernet's max packet size is 1500 bytes, 1500 - 48 = 1452.
|
||||
const MaxPacketBufferSize ByteCount = 1452
|
||||
const MaxPacketBufferSize = 1452
|
||||
|
||||
// MaxLargePacketBufferSize is used when using GSO
|
||||
const MaxLargePacketBufferSize = 20 * 1024
|
||||
|
||||
// MinInitialPacketSize is the minimum size an Initial packet is required to have.
|
||||
const MinInitialPacketSize = 1200
|
||||
@@ -77,6 +129,9 @@ const MinConnectionIDLenInitial = 8
|
||||
// DefaultAckDelayExponent is the default ack delay exponent
|
||||
const DefaultAckDelayExponent = 3
|
||||
|
||||
// DefaultActiveConnectionIDLimit is the default active connection ID limit
|
||||
const DefaultActiveConnectionIDLimit = 2
|
||||
|
||||
// MaxAckDelayExponent is the maximum ack delay exponent
|
||||
const MaxAckDelayExponent = 20
|
||||
|
||||
|
||||
6
vendor/github.com/quic-go/quic-go/internal/protocol/version.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/protocol/version.go
generated
vendored
@@ -19,14 +19,14 @@ const (
|
||||
// The version numbers, making grepping easier
|
||||
const (
|
||||
VersionUnknown VersionNumber = math.MaxUint32
|
||||
VersionDraft29 VersionNumber = 0xff00001d
|
||||
versionDraft29 VersionNumber = 0xff00001d // draft-29 used to be a widely deployed version
|
||||
Version1 VersionNumber = 0x1
|
||||
Version2 VersionNumber = 0x6b3343cf
|
||||
)
|
||||
|
||||
// SupportedVersions lists the versions that the server supports
|
||||
// must be in sorted descending order
|
||||
var SupportedVersions = []VersionNumber{Version1, Version2, VersionDraft29}
|
||||
var SupportedVersions = []VersionNumber{Version1, Version2}
|
||||
|
||||
// IsValidVersion says if the version is known to quic-go
|
||||
func IsValidVersion(v VersionNumber) bool {
|
||||
@@ -38,7 +38,7 @@ func (vn VersionNumber) String() string {
|
||||
switch vn {
|
||||
case VersionUnknown:
|
||||
return "unknown"
|
||||
case VersionDraft29:
|
||||
case versionDraft29:
|
||||
return "draft-29"
|
||||
case Version1:
|
||||
return "v1"
|
||||
|
||||
2
vendor/github.com/quic-go/quic-go/internal/qerr/error_codes.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/internal/qerr/error_codes.go
generated
vendored
@@ -40,7 +40,7 @@ func (e TransportErrorCode) Message() string {
|
||||
if !e.IsCryptoError() {
|
||||
return ""
|
||||
}
|
||||
return qtls.Alert(e - 0x100).Error()
|
||||
return qtls.AlertError(e - 0x100).Error()
|
||||
}
|
||||
|
||||
func (e TransportErrorCode) String() string {
|
||||
|
||||
14
vendor/github.com/quic-go/quic-go/internal/qerr/errors.go
generated
vendored
14
vendor/github.com/quic-go/quic-go/internal/qerr/errors.go
generated
vendored
@@ -17,15 +17,16 @@ type TransportError struct {
|
||||
FrameType uint64
|
||||
ErrorCode TransportErrorCode
|
||||
ErrorMessage string
|
||||
error error // only set for local errors, sometimes
|
||||
}
|
||||
|
||||
var _ error = &TransportError{}
|
||||
|
||||
// NewLocalCryptoError create a new TransportError instance for a crypto error
|
||||
func NewLocalCryptoError(tlsAlert uint8, errorMessage string) *TransportError {
|
||||
func NewLocalCryptoError(tlsAlert uint8, err error) *TransportError {
|
||||
return &TransportError{
|
||||
ErrorCode: 0x100 + TransportErrorCode(tlsAlert),
|
||||
ErrorMessage: errorMessage,
|
||||
ErrorCode: 0x100 + TransportErrorCode(tlsAlert),
|
||||
error: err,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +36,9 @@ func (e *TransportError) Error() string {
|
||||
str += fmt.Sprintf(" (frame type: %#x)", e.FrameType)
|
||||
}
|
||||
msg := e.ErrorMessage
|
||||
if len(msg) == 0 && e.error != nil {
|
||||
msg = e.error.Error()
|
||||
}
|
||||
if len(msg) == 0 {
|
||||
msg = e.ErrorCode.Message()
|
||||
}
|
||||
@@ -48,6 +52,10 @@ func (e *TransportError) Is(target error) bool {
|
||||
return target == net.ErrClosed
|
||||
}
|
||||
|
||||
func (e *TransportError) Unwrap() error {
|
||||
return e.error
|
||||
}
|
||||
|
||||
// An ApplicationErrorCode is an application-defined error code.
|
||||
type ApplicationErrorCode uint64
|
||||
|
||||
|
||||
66
vendor/github.com/quic-go/quic-go/internal/qtls/cipher_suite_go121.go
generated
vendored
Normal file
66
vendor/github.com/quic-go/quic-go/internal/qtls/cipher_suite_go121.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
//go:build go1.21
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/cipher"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type cipherSuiteTLS13 struct {
|
||||
ID uint16
|
||||
KeyLen int
|
||||
AEAD func(key, fixedNonce []byte) cipher.AEAD
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
//go:linkname cipherSuiteTLS13ByID crypto/tls.cipherSuiteTLS13ByID
|
||||
func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13
|
||||
|
||||
//go:linkname cipherSuitesTLS13 crypto/tls.cipherSuitesTLS13
|
||||
var cipherSuitesTLS13 []unsafe.Pointer
|
||||
|
||||
//go:linkname defaultCipherSuitesTLS13 crypto/tls.defaultCipherSuitesTLS13
|
||||
var defaultCipherSuitesTLS13 []uint16
|
||||
|
||||
//go:linkname defaultCipherSuitesTLS13NoAES crypto/tls.defaultCipherSuitesTLS13NoAES
|
||||
var defaultCipherSuitesTLS13NoAES []uint16
|
||||
|
||||
var cipherSuitesModified bool
|
||||
|
||||
// SetCipherSuite modifies the cipherSuiteTLS13 slice of cipher suites inside qtls
|
||||
// such that it only contains the cipher suite with the chosen id.
|
||||
// The reset function returned resets them back to the original value.
|
||||
func SetCipherSuite(id uint16) (reset func()) {
|
||||
if cipherSuitesModified {
|
||||
panic("cipher suites modified multiple times without resetting")
|
||||
}
|
||||
cipherSuitesModified = true
|
||||
|
||||
origCipherSuitesTLS13 := append([]unsafe.Pointer{}, cipherSuitesTLS13...)
|
||||
origDefaultCipherSuitesTLS13 := append([]uint16{}, defaultCipherSuitesTLS13...)
|
||||
origDefaultCipherSuitesTLS13NoAES := append([]uint16{}, defaultCipherSuitesTLS13NoAES...)
|
||||
// The order is given by the order of the slice elements in cipherSuitesTLS13 in qtls.
|
||||
switch id {
|
||||
case tls.TLS_AES_128_GCM_SHA256:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[:1]
|
||||
case tls.TLS_CHACHA20_POLY1305_SHA256:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[1:2]
|
||||
case tls.TLS_AES_256_GCM_SHA384:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[2:]
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected cipher suite: %d", id))
|
||||
}
|
||||
defaultCipherSuitesTLS13 = []uint16{id}
|
||||
defaultCipherSuitesTLS13NoAES = []uint16{id}
|
||||
|
||||
return func() {
|
||||
cipherSuitesTLS13 = origCipherSuitesTLS13
|
||||
defaultCipherSuitesTLS13 = origDefaultCipherSuitesTLS13
|
||||
defaultCipherSuitesTLS13NoAES = origDefaultCipherSuitesTLS13NoAES
|
||||
cipherSuitesModified = false
|
||||
}
|
||||
}
|
||||
63
vendor/github.com/quic-go/quic-go/internal/qtls/client_session_cache.go
generated
vendored
Normal file
63
vendor/github.com/quic-go/quic-go/internal/qtls/client_session_cache.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
//go:build go1.21
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
)
|
||||
|
||||
type clientSessionCache struct {
|
||||
getData func() []byte
|
||||
setData func([]byte) (allowEarlyData bool)
|
||||
wrapped tls.ClientSessionCache
|
||||
}
|
||||
|
||||
var _ tls.ClientSessionCache = &clientSessionCache{}
|
||||
|
||||
func (c clientSessionCache) Put(key string, cs *tls.ClientSessionState) {
|
||||
if cs == nil {
|
||||
c.wrapped.Put(key, nil)
|
||||
return
|
||||
}
|
||||
ticket, state, err := cs.ResumptionState()
|
||||
if err != nil || state == nil {
|
||||
c.wrapped.Put(key, cs)
|
||||
return
|
||||
}
|
||||
state.Extra = append(state.Extra, addExtraPrefix(c.getData()))
|
||||
newCS, err := tls.NewResumptionState(ticket, state)
|
||||
if err != nil {
|
||||
// It's not clear why this would error. Just save the original state.
|
||||
c.wrapped.Put(key, cs)
|
||||
return
|
||||
}
|
||||
c.wrapped.Put(key, newCS)
|
||||
}
|
||||
|
||||
func (c clientSessionCache) Get(key string) (*tls.ClientSessionState, bool) {
|
||||
cs, ok := c.wrapped.Get(key)
|
||||
if !ok || cs == nil {
|
||||
return cs, ok
|
||||
}
|
||||
ticket, state, err := cs.ResumptionState()
|
||||
if err != nil {
|
||||
// It's not clear why this would error.
|
||||
// Remove the ticket from the session cache, so we don't run into this error over and over again
|
||||
c.wrapped.Put(key, nil)
|
||||
return nil, false
|
||||
}
|
||||
var earlyData bool
|
||||
// restore QUIC transport parameters and RTT stored in state.Extra
|
||||
if extra := findExtraData(state.Extra); extra != nil {
|
||||
earlyData = c.setData(extra)
|
||||
}
|
||||
state.EarlyData = earlyData
|
||||
session, err := tls.NewResumptionState(ticket, state)
|
||||
if err != nil {
|
||||
// It's not clear why this would error.
|
||||
// Remove the ticket from the session cache, so we don't run into this error over and over again
|
||||
c.wrapped.Put(key, nil)
|
||||
return nil, false
|
||||
}
|
||||
return session, true
|
||||
}
|
||||
145
vendor/github.com/quic-go/quic-go/internal/qtls/go119.go
generated
vendored
145
vendor/github.com/quic-go/quic-go/internal/qtls/go119.go
generated
vendored
@@ -1,145 +0,0 @@
|
||||
//go:build go1.19 && !go1.20
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/cipher"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"unsafe"
|
||||
|
||||
"github.com/quic-go/qtls-go1-19"
|
||||
)
|
||||
|
||||
type (
|
||||
// Alert is a TLS alert
|
||||
Alert = qtls.Alert
|
||||
// A Certificate is qtls.Certificate.
|
||||
Certificate = qtls.Certificate
|
||||
// CertificateRequestInfo contains information about a certificate request.
|
||||
CertificateRequestInfo = qtls.CertificateRequestInfo
|
||||
// A CipherSuiteTLS13 is a cipher suite for TLS 1.3
|
||||
CipherSuiteTLS13 = qtls.CipherSuiteTLS13
|
||||
// ClientHelloInfo contains information about a ClientHello.
|
||||
ClientHelloInfo = qtls.ClientHelloInfo
|
||||
// ClientSessionCache is a cache used for session resumption.
|
||||
ClientSessionCache = qtls.ClientSessionCache
|
||||
// ClientSessionState is a state needed for session resumption.
|
||||
ClientSessionState = qtls.ClientSessionState
|
||||
// A Config is a qtls.Config.
|
||||
Config = qtls.Config
|
||||
// A Conn is a qtls.Conn.
|
||||
Conn = qtls.Conn
|
||||
// ConnectionState contains information about the state of the connection.
|
||||
ConnectionState = qtls.ConnectionStateWith0RTT
|
||||
// EncryptionLevel is the encryption level of a message.
|
||||
EncryptionLevel = qtls.EncryptionLevel
|
||||
// Extension is a TLS extension
|
||||
Extension = qtls.Extension
|
||||
// ExtraConfig is the qtls.ExtraConfig
|
||||
ExtraConfig = qtls.ExtraConfig
|
||||
// RecordLayer is a qtls RecordLayer.
|
||||
RecordLayer = qtls.RecordLayer
|
||||
)
|
||||
|
||||
const (
|
||||
// EncryptionHandshake is the Handshake encryption level
|
||||
EncryptionHandshake = qtls.EncryptionHandshake
|
||||
// Encryption0RTT is the 0-RTT encryption level
|
||||
Encryption0RTT = qtls.Encryption0RTT
|
||||
// EncryptionApplication is the application data encryption level
|
||||
EncryptionApplication = qtls.EncryptionApplication
|
||||
)
|
||||
|
||||
// AEADAESGCMTLS13 creates a new AES-GCM AEAD for TLS 1.3
|
||||
func AEADAESGCMTLS13(key, fixedNonce []byte) cipher.AEAD {
|
||||
return qtls.AEADAESGCMTLS13(key, fixedNonce)
|
||||
}
|
||||
|
||||
// Client returns a new TLS client side connection.
|
||||
func Client(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
return qtls.Client(conn, config, extraConfig)
|
||||
}
|
||||
|
||||
// Server returns a new TLS server side connection.
|
||||
func Server(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
return qtls.Server(conn, config, extraConfig)
|
||||
}
|
||||
|
||||
func GetConnectionState(conn *Conn) ConnectionState {
|
||||
return conn.ConnectionStateWith0RTT()
|
||||
}
|
||||
|
||||
// ToTLSConnectionState extracts the tls.ConnectionState
|
||||
func ToTLSConnectionState(cs ConnectionState) tls.ConnectionState {
|
||||
return cs.ConnectionState
|
||||
}
|
||||
|
||||
type cipherSuiteTLS13 struct {
|
||||
ID uint16
|
||||
KeyLen int
|
||||
AEAD func(key, fixedNonce []byte) cipher.AEAD
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
//go:linkname cipherSuiteTLS13ByID github.com/quic-go/qtls-go1-19.cipherSuiteTLS13ByID
|
||||
func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13
|
||||
|
||||
// CipherSuiteTLS13ByID gets a TLS 1.3 cipher suite.
|
||||
func CipherSuiteTLS13ByID(id uint16) *CipherSuiteTLS13 {
|
||||
val := cipherSuiteTLS13ByID(id)
|
||||
cs := (*cipherSuiteTLS13)(unsafe.Pointer(val))
|
||||
return &qtls.CipherSuiteTLS13{
|
||||
ID: cs.ID,
|
||||
KeyLen: cs.KeyLen,
|
||||
AEAD: cs.AEAD,
|
||||
Hash: cs.Hash,
|
||||
}
|
||||
}
|
||||
|
||||
//go:linkname cipherSuitesTLS13 github.com/quic-go/qtls-go1-19.cipherSuitesTLS13
|
||||
var cipherSuitesTLS13 []unsafe.Pointer
|
||||
|
||||
//go:linkname defaultCipherSuitesTLS13 github.com/quic-go/qtls-go1-19.defaultCipherSuitesTLS13
|
||||
var defaultCipherSuitesTLS13 []uint16
|
||||
|
||||
//go:linkname defaultCipherSuitesTLS13NoAES github.com/quic-go/qtls-go1-19.defaultCipherSuitesTLS13NoAES
|
||||
var defaultCipherSuitesTLS13NoAES []uint16
|
||||
|
||||
var cipherSuitesModified bool
|
||||
|
||||
// SetCipherSuite modifies the cipherSuiteTLS13 slice of cipher suites inside qtls
|
||||
// such that it only contains the cipher suite with the chosen id.
|
||||
// The reset function returned resets them back to the original value.
|
||||
func SetCipherSuite(id uint16) (reset func()) {
|
||||
if cipherSuitesModified {
|
||||
panic("cipher suites modified multiple times without resetting")
|
||||
}
|
||||
cipherSuitesModified = true
|
||||
|
||||
origCipherSuitesTLS13 := append([]unsafe.Pointer{}, cipherSuitesTLS13...)
|
||||
origDefaultCipherSuitesTLS13 := append([]uint16{}, defaultCipherSuitesTLS13...)
|
||||
origDefaultCipherSuitesTLS13NoAES := append([]uint16{}, defaultCipherSuitesTLS13NoAES...)
|
||||
// The order is given by the order of the slice elements in cipherSuitesTLS13 in qtls.
|
||||
switch id {
|
||||
case tls.TLS_AES_128_GCM_SHA256:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[:1]
|
||||
case tls.TLS_CHACHA20_POLY1305_SHA256:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[1:2]
|
||||
case tls.TLS_AES_256_GCM_SHA384:
|
||||
cipherSuitesTLS13 = cipherSuitesTLS13[2:]
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected cipher suite: %d", id))
|
||||
}
|
||||
defaultCipherSuitesTLS13 = []uint16{id}
|
||||
defaultCipherSuitesTLS13NoAES = []uint16{id}
|
||||
|
||||
return func() {
|
||||
cipherSuitesTLS13 = origCipherSuitesTLS13
|
||||
defaultCipherSuitesTLS13 = origDefaultCipherSuitesTLS13
|
||||
defaultCipherSuitesTLS13NoAES = origDefaultCipherSuitesTLS13NoAES
|
||||
cipherSuitesModified = false
|
||||
}
|
||||
}
|
||||
144
vendor/github.com/quic-go/quic-go/internal/qtls/go120.go
generated
vendored
144
vendor/github.com/quic-go/quic-go/internal/qtls/go120.go
generated
vendored
@@ -1,101 +1,99 @@
|
||||
//go:build go1.20
|
||||
//go:build go1.20 && !go1.21
|
||||
|
||||
package qtls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/cipher"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"unsafe"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
|
||||
"github.com/quic-go/qtls-go1-20"
|
||||
)
|
||||
|
||||
type (
|
||||
// Alert is a TLS alert
|
||||
Alert = qtls.Alert
|
||||
// A Certificate is qtls.Certificate.
|
||||
Certificate = qtls.Certificate
|
||||
// CertificateRequestInfo contains information about a certificate request.
|
||||
CertificateRequestInfo = qtls.CertificateRequestInfo
|
||||
// A CipherSuiteTLS13 is a cipher suite for TLS 1.3
|
||||
CipherSuiteTLS13 = qtls.CipherSuiteTLS13
|
||||
// ClientHelloInfo contains information about a ClientHello.
|
||||
ClientHelloInfo = qtls.ClientHelloInfo
|
||||
// ClientSessionCache is a cache used for session resumption.
|
||||
ClientSessionCache = qtls.ClientSessionCache
|
||||
// ClientSessionState is a state needed for session resumption.
|
||||
ClientSessionState = qtls.ClientSessionState
|
||||
// A Config is a qtls.Config.
|
||||
Config = qtls.Config
|
||||
// A Conn is a qtls.Conn.
|
||||
Conn = qtls.Conn
|
||||
// ConnectionState contains information about the state of the connection.
|
||||
ConnectionState = qtls.ConnectionStateWith0RTT
|
||||
// EncryptionLevel is the encryption level of a message.
|
||||
EncryptionLevel = qtls.EncryptionLevel
|
||||
// Extension is a TLS extension
|
||||
Extension = qtls.Extension
|
||||
// ExtraConfig is the qtls.ExtraConfig
|
||||
ExtraConfig = qtls.ExtraConfig
|
||||
// RecordLayer is a qtls RecordLayer.
|
||||
RecordLayer = qtls.RecordLayer
|
||||
QUICConn = qtls.QUICConn
|
||||
QUICConfig = qtls.QUICConfig
|
||||
QUICEvent = qtls.QUICEvent
|
||||
QUICEventKind = qtls.QUICEventKind
|
||||
QUICEncryptionLevel = qtls.QUICEncryptionLevel
|
||||
AlertError = qtls.AlertError
|
||||
)
|
||||
|
||||
const (
|
||||
// EncryptionHandshake is the Handshake encryption level
|
||||
EncryptionHandshake = qtls.EncryptionHandshake
|
||||
// Encryption0RTT is the 0-RTT encryption level
|
||||
Encryption0RTT = qtls.Encryption0RTT
|
||||
// EncryptionApplication is the application data encryption level
|
||||
EncryptionApplication = qtls.EncryptionApplication
|
||||
QUICEncryptionLevelInitial = qtls.QUICEncryptionLevelInitial
|
||||
QUICEncryptionLevelEarly = qtls.QUICEncryptionLevelEarly
|
||||
QUICEncryptionLevelHandshake = qtls.QUICEncryptionLevelHandshake
|
||||
QUICEncryptionLevelApplication = qtls.QUICEncryptionLevelApplication
|
||||
)
|
||||
|
||||
// AEADAESGCMTLS13 creates a new AES-GCM AEAD for TLS 1.3
|
||||
func AEADAESGCMTLS13(key, fixedNonce []byte) cipher.AEAD {
|
||||
return qtls.AEADAESGCMTLS13(key, fixedNonce)
|
||||
const (
|
||||
QUICNoEvent = qtls.QUICNoEvent
|
||||
QUICSetReadSecret = qtls.QUICSetReadSecret
|
||||
QUICSetWriteSecret = qtls.QUICSetWriteSecret
|
||||
QUICWriteData = qtls.QUICWriteData
|
||||
QUICTransportParameters = qtls.QUICTransportParameters
|
||||
QUICTransportParametersRequired = qtls.QUICTransportParametersRequired
|
||||
QUICRejectedEarlyData = qtls.QUICRejectedEarlyData
|
||||
QUICHandshakeDone = qtls.QUICHandshakeDone
|
||||
)
|
||||
|
||||
func SetupConfigForServer(conf *QUICConfig, enable0RTT bool, getDataForSessionTicket func() []byte, handleSessionTicket func([]byte, bool) bool) {
|
||||
qtls.InitSessionTicketKeys(conf.TLSConfig)
|
||||
conf.TLSConfig = conf.TLSConfig.Clone()
|
||||
conf.TLSConfig.MinVersion = tls.VersionTLS13
|
||||
conf.ExtraConfig = &qtls.ExtraConfig{
|
||||
Enable0RTT: enable0RTT,
|
||||
Accept0RTT: func(data []byte) bool {
|
||||
return handleSessionTicket(data, true)
|
||||
},
|
||||
GetAppDataForSessionTicket: getDataForSessionTicket,
|
||||
}
|
||||
}
|
||||
|
||||
// Client returns a new TLS client side connection.
|
||||
func Client(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
return qtls.Client(conn, config, extraConfig)
|
||||
func SetupConfigForClient(conf *QUICConfig, getDataForSessionState func() []byte, setDataFromSessionState func([]byte) bool) {
|
||||
conf.ExtraConfig = &qtls.ExtraConfig{
|
||||
GetAppDataForSessionState: getDataForSessionState,
|
||||
SetAppDataFromSessionState: setDataFromSessionState,
|
||||
}
|
||||
}
|
||||
|
||||
// Server returns a new TLS server side connection.
|
||||
func Server(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
|
||||
return qtls.Server(conn, config, extraConfig)
|
||||
func QUICServer(config *QUICConfig) *QUICConn {
|
||||
return qtls.QUICServer(config)
|
||||
}
|
||||
|
||||
func GetConnectionState(conn *Conn) ConnectionState {
|
||||
return conn.ConnectionStateWith0RTT()
|
||||
func QUICClient(config *QUICConfig) *QUICConn {
|
||||
return qtls.QUICClient(config)
|
||||
}
|
||||
|
||||
// ToTLSConnectionState extracts the tls.ConnectionState
|
||||
func ToTLSConnectionState(cs ConnectionState) tls.ConnectionState {
|
||||
return cs.ConnectionState
|
||||
func ToTLSEncryptionLevel(e protocol.EncryptionLevel) qtls.QUICEncryptionLevel {
|
||||
switch e {
|
||||
case protocol.EncryptionInitial:
|
||||
return qtls.QUICEncryptionLevelInitial
|
||||
case protocol.EncryptionHandshake:
|
||||
return qtls.QUICEncryptionLevelHandshake
|
||||
case protocol.Encryption1RTT:
|
||||
return qtls.QUICEncryptionLevelApplication
|
||||
case protocol.Encryption0RTT:
|
||||
return qtls.QUICEncryptionLevelEarly
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected encryption level: %s", e))
|
||||
}
|
||||
}
|
||||
|
||||
type cipherSuiteTLS13 struct {
|
||||
ID uint16
|
||||
KeyLen int
|
||||
AEAD func(key, fixedNonce []byte) cipher.AEAD
|
||||
Hash crypto.Hash
|
||||
}
|
||||
|
||||
//go:linkname cipherSuiteTLS13ByID github.com/quic-go/qtls-go1-20.cipherSuiteTLS13ByID
|
||||
func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13
|
||||
|
||||
// CipherSuiteTLS13ByID gets a TLS 1.3 cipher suite.
|
||||
func CipherSuiteTLS13ByID(id uint16) *CipherSuiteTLS13 {
|
||||
val := cipherSuiteTLS13ByID(id)
|
||||
cs := (*cipherSuiteTLS13)(unsafe.Pointer(val))
|
||||
return &qtls.CipherSuiteTLS13{
|
||||
ID: cs.ID,
|
||||
KeyLen: cs.KeyLen,
|
||||
AEAD: cs.AEAD,
|
||||
Hash: cs.Hash,
|
||||
func FromTLSEncryptionLevel(e qtls.QUICEncryptionLevel) protocol.EncryptionLevel {
|
||||
switch e {
|
||||
case qtls.QUICEncryptionLevelInitial:
|
||||
return protocol.EncryptionInitial
|
||||
case qtls.QUICEncryptionLevelHandshake:
|
||||
return protocol.EncryptionHandshake
|
||||
case qtls.QUICEncryptionLevelApplication:
|
||||
return protocol.Encryption1RTT
|
||||
case qtls.QUICEncryptionLevelEarly:
|
||||
return protocol.Encryption0RTT
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpect encryption level: %s", e))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,3 +141,7 @@ func SetCipherSuite(id uint16) (reset func()) {
|
||||
cipherSuitesModified = false
|
||||
}
|
||||
}
|
||||
|
||||
func SendSessionTicket(c *QUICConn, allow0RTT bool) error {
|
||||
return c.SendSessionTicket(allow0RTT)
|
||||
}
|
||||
|
||||
156
vendor/github.com/quic-go/quic-go/internal/qtls/go121.go
generated
vendored
156
vendor/github.com/quic-go/quic-go/internal/qtls/go121.go
generated
vendored
@@ -2,4 +2,158 @@
|
||||
|
||||
package qtls
|
||||
|
||||
var _ int = "The version of quic-go you're using can't be built on Go 1.21 yet. For more details, please see https://github.com/quic-go/quic-go/wiki/quic-go-and-Go-versions."
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
)
|
||||
|
||||
type (
|
||||
QUICConn = tls.QUICConn
|
||||
QUICConfig = tls.QUICConfig
|
||||
QUICEvent = tls.QUICEvent
|
||||
QUICEventKind = tls.QUICEventKind
|
||||
QUICEncryptionLevel = tls.QUICEncryptionLevel
|
||||
QUICSessionTicketOptions = tls.QUICSessionTicketOptions
|
||||
AlertError = tls.AlertError
|
||||
)
|
||||
|
||||
const (
|
||||
QUICEncryptionLevelInitial = tls.QUICEncryptionLevelInitial
|
||||
QUICEncryptionLevelEarly = tls.QUICEncryptionLevelEarly
|
||||
QUICEncryptionLevelHandshake = tls.QUICEncryptionLevelHandshake
|
||||
QUICEncryptionLevelApplication = tls.QUICEncryptionLevelApplication
|
||||
)
|
||||
|
||||
const (
|
||||
QUICNoEvent = tls.QUICNoEvent
|
||||
QUICSetReadSecret = tls.QUICSetReadSecret
|
||||
QUICSetWriteSecret = tls.QUICSetWriteSecret
|
||||
QUICWriteData = tls.QUICWriteData
|
||||
QUICTransportParameters = tls.QUICTransportParameters
|
||||
QUICTransportParametersRequired = tls.QUICTransportParametersRequired
|
||||
QUICRejectedEarlyData = tls.QUICRejectedEarlyData
|
||||
QUICHandshakeDone = tls.QUICHandshakeDone
|
||||
)
|
||||
|
||||
func QUICServer(config *QUICConfig) *QUICConn { return tls.QUICServer(config) }
|
||||
func QUICClient(config *QUICConfig) *QUICConn { return tls.QUICClient(config) }
|
||||
|
||||
func SetupConfigForServer(qconf *QUICConfig, _ bool, getData func() []byte, handleSessionTicket func([]byte, bool) bool) {
|
||||
conf := qconf.TLSConfig
|
||||
|
||||
// Workaround for https://github.com/golang/go/issues/60506.
|
||||
// This initializes the session tickets _before_ cloning the config.
|
||||
_, _ = conf.DecryptTicket(nil, tls.ConnectionState{})
|
||||
|
||||
conf = conf.Clone()
|
||||
conf.MinVersion = tls.VersionTLS13
|
||||
qconf.TLSConfig = conf
|
||||
|
||||
// add callbacks to save transport parameters into the session ticket
|
||||
origWrapSession := conf.WrapSession
|
||||
conf.WrapSession = func(cs tls.ConnectionState, state *tls.SessionState) ([]byte, error) {
|
||||
// Add QUIC session ticket
|
||||
state.Extra = append(state.Extra, addExtraPrefix(getData()))
|
||||
|
||||
if origWrapSession != nil {
|
||||
return origWrapSession(cs, state)
|
||||
}
|
||||
b, err := conf.EncryptTicket(cs, state)
|
||||
return b, err
|
||||
}
|
||||
origUnwrapSession := conf.UnwrapSession
|
||||
// UnwrapSession might be called multiple times, as the client can use multiple session tickets.
|
||||
// However, using 0-RTT is only possible with the first session ticket.
|
||||
// crypto/tls guarantees that this callback is called in the same order as the session ticket in the ClientHello.
|
||||
var unwrapCount int
|
||||
conf.UnwrapSession = func(identity []byte, connState tls.ConnectionState) (*tls.SessionState, error) {
|
||||
unwrapCount++
|
||||
var state *tls.SessionState
|
||||
var err error
|
||||
if origUnwrapSession != nil {
|
||||
state, err = origUnwrapSession(identity, connState)
|
||||
} else {
|
||||
state, err = conf.DecryptTicket(identity, connState)
|
||||
}
|
||||
if err != nil || state == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
extra := findExtraData(state.Extra)
|
||||
if extra != nil {
|
||||
state.EarlyData = handleSessionTicket(extra, state.EarlyData && unwrapCount == 1)
|
||||
} else {
|
||||
state.EarlyData = false
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
}
|
||||
|
||||
func SetupConfigForClient(qconf *QUICConfig, getData func() []byte, setData func([]byte) bool) {
|
||||
conf := qconf.TLSConfig
|
||||
if conf.ClientSessionCache != nil {
|
||||
origCache := conf.ClientSessionCache
|
||||
conf.ClientSessionCache = &clientSessionCache{
|
||||
wrapped: origCache,
|
||||
getData: getData,
|
||||
setData: setData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ToTLSEncryptionLevel(e protocol.EncryptionLevel) tls.QUICEncryptionLevel {
|
||||
switch e {
|
||||
case protocol.EncryptionInitial:
|
||||
return tls.QUICEncryptionLevelInitial
|
||||
case protocol.EncryptionHandshake:
|
||||
return tls.QUICEncryptionLevelHandshake
|
||||
case protocol.Encryption1RTT:
|
||||
return tls.QUICEncryptionLevelApplication
|
||||
case protocol.Encryption0RTT:
|
||||
return tls.QUICEncryptionLevelEarly
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected encryption level: %s", e))
|
||||
}
|
||||
}
|
||||
|
||||
func FromTLSEncryptionLevel(e tls.QUICEncryptionLevel) protocol.EncryptionLevel {
|
||||
switch e {
|
||||
case tls.QUICEncryptionLevelInitial:
|
||||
return protocol.EncryptionInitial
|
||||
case tls.QUICEncryptionLevelHandshake:
|
||||
return protocol.EncryptionHandshake
|
||||
case tls.QUICEncryptionLevelApplication:
|
||||
return protocol.Encryption1RTT
|
||||
case tls.QUICEncryptionLevelEarly:
|
||||
return protocol.Encryption0RTT
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpect encryption level: %s", e))
|
||||
}
|
||||
}
|
||||
|
||||
const extraPrefix = "quic-go1"
|
||||
|
||||
func addExtraPrefix(b []byte) []byte {
|
||||
return append([]byte(extraPrefix), b...)
|
||||
}
|
||||
|
||||
func findExtraData(extras [][]byte) []byte {
|
||||
prefix := []byte(extraPrefix)
|
||||
for _, extra := range extras {
|
||||
if len(extra) < len(prefix) || !bytes.Equal(prefix, extra[:len(prefix)]) {
|
||||
continue
|
||||
}
|
||||
return extra[len(prefix):]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SendSessionTicket(c *QUICConn, allow0RTT bool) error {
|
||||
return c.SendSessionTicket(tls.QUICSessionTicketOptions{
|
||||
EarlyData: allow0RTT,
|
||||
})
|
||||
}
|
||||
|
||||
2
vendor/github.com/quic-go/quic-go/internal/qtls/go_oldversion.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/internal/qtls/go_oldversion.go
generated
vendored
@@ -1,4 +1,4 @@
|
||||
//go:build !go1.19
|
||||
//go:build !go1.20
|
||||
|
||||
package qtls
|
||||
|
||||
|
||||
86
vendor/github.com/quic-go/quic-go/internal/utils/ringbuffer/ringbuffer.go
generated
vendored
Normal file
86
vendor/github.com/quic-go/quic-go/internal/utils/ringbuffer/ringbuffer.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package ringbuffer
|
||||
|
||||
// A RingBuffer is a ring buffer.
|
||||
// It acts as a heap that doesn't cause any allocations.
|
||||
type RingBuffer[T any] struct {
|
||||
ring []T
|
||||
headPos, tailPos int
|
||||
full bool
|
||||
}
|
||||
|
||||
// Init preallocs a buffer with a certain size.
|
||||
func (r *RingBuffer[T]) Init(size int) {
|
||||
r.ring = make([]T, size)
|
||||
}
|
||||
|
||||
// Len returns the number of elements in the ring buffer.
|
||||
func (r *RingBuffer[T]) Len() int {
|
||||
if r.full {
|
||||
return len(r.ring)
|
||||
}
|
||||
if r.tailPos >= r.headPos {
|
||||
return r.tailPos - r.headPos
|
||||
}
|
||||
return r.tailPos - r.headPos + len(r.ring)
|
||||
}
|
||||
|
||||
// Empty says if the ring buffer is empty.
|
||||
func (r *RingBuffer[T]) Empty() bool {
|
||||
return !r.full && r.headPos == r.tailPos
|
||||
}
|
||||
|
||||
// PushBack adds a new element.
|
||||
// If the ring buffer is full, its capacity is increased first.
|
||||
func (r *RingBuffer[T]) PushBack(t T) {
|
||||
if r.full || len(r.ring) == 0 {
|
||||
r.grow()
|
||||
}
|
||||
r.ring[r.tailPos] = t
|
||||
r.tailPos++
|
||||
if r.tailPos == len(r.ring) {
|
||||
r.tailPos = 0
|
||||
}
|
||||
if r.tailPos == r.headPos {
|
||||
r.full = true
|
||||
}
|
||||
}
|
||||
|
||||
// PopFront returns the next element.
|
||||
// It must not be called when the buffer is empty, that means that
|
||||
// callers might need to check if there are elements in the buffer first.
|
||||
func (r *RingBuffer[T]) PopFront() T {
|
||||
if r.Empty() {
|
||||
panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: pop from an empty queue")
|
||||
}
|
||||
r.full = false
|
||||
t := r.ring[r.headPos]
|
||||
r.ring[r.headPos] = *new(T)
|
||||
r.headPos++
|
||||
if r.headPos == len(r.ring) {
|
||||
r.headPos = 0
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Grow the maximum size of the queue.
|
||||
// This method assume the queue is full.
|
||||
func (r *RingBuffer[T]) grow() {
|
||||
oldRing := r.ring
|
||||
newSize := len(oldRing) * 2
|
||||
if newSize == 0 {
|
||||
newSize = 1
|
||||
}
|
||||
r.ring = make([]T, newSize)
|
||||
headLen := copy(r.ring, oldRing[r.headPos:])
|
||||
copy(r.ring[headLen:], oldRing[:r.headPos])
|
||||
r.headPos, r.tailPos, r.full = 0, len(oldRing), false
|
||||
}
|
||||
|
||||
// Clear removes all elements.
|
||||
func (r *RingBuffer[T]) Clear() {
|
||||
var zeroValue T
|
||||
for i := range r.ring {
|
||||
r.ring[i] = zeroValue
|
||||
}
|
||||
r.headPos, r.tailPos, r.full = 0, 0, false
|
||||
}
|
||||
6
vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
generated
vendored
@@ -103,8 +103,12 @@ func (r *RTTStats) SetMaxAckDelay(mad time.Duration) {
|
||||
// SetInitialRTT sets the initial RTT.
|
||||
// It is used during the 0-RTT handshake when restoring the RTT stats from the session state.
|
||||
func (r *RTTStats) SetInitialRTT(t time.Duration) {
|
||||
// On the server side, by the time we get to process the session ticket,
|
||||
// we might already have obtained an RTT measurement.
|
||||
// This can happen if we received the ClientHello in multiple pieces, and one of those pieces was lost.
|
||||
// Discard the restored value. A fresh measurement is always better.
|
||||
if r.hasMeasurement {
|
||||
panic("initial RTT set after first measurement")
|
||||
return
|
||||
}
|
||||
r.smoothedRTT = t
|
||||
r.latestRTT = t
|
||||
|
||||
57
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
generated
vendored
57
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
generated
vendored
@@ -22,19 +22,17 @@ type AckFrame struct {
|
||||
}
|
||||
|
||||
// parseAckFrame reads an ACK frame
|
||||
func parseAckFrame(r *bytes.Reader, typ uint64, ackDelayExponent uint8, _ protocol.VersionNumber) (*AckFrame, error) {
|
||||
func parseAckFrame(frame *AckFrame, r *bytes.Reader, typ uint64, ackDelayExponent uint8, _ protocol.VersionNumber) error {
|
||||
ecn := typ == ackECNFrameType
|
||||
|
||||
frame := GetAckFrame()
|
||||
|
||||
la, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
largestAcked := protocol.PacketNumber(la)
|
||||
delay, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
delayTime := time.Duration(delay*1<<ackDelayExponent) * time.Microsecond
|
||||
@@ -46,17 +44,17 @@ func parseAckFrame(r *bytes.Reader, typ uint64, ackDelayExponent uint8, _ protoc
|
||||
|
||||
numBlocks, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
// read the first ACK range
|
||||
ab, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
ackBlock := protocol.PacketNumber(ab)
|
||||
if ackBlock > largestAcked {
|
||||
return nil, errors.New("invalid first ACK range")
|
||||
return errors.New("invalid first ACK range")
|
||||
}
|
||||
smallest := largestAcked - ackBlock
|
||||
|
||||
@@ -65,41 +63,50 @@ func parseAckFrame(r *bytes.Reader, typ uint64, ackDelayExponent uint8, _ protoc
|
||||
for i := uint64(0); i < numBlocks; i++ {
|
||||
g, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
gap := protocol.PacketNumber(g)
|
||||
if smallest < gap+2 {
|
||||
return nil, errInvalidAckRanges
|
||||
return errInvalidAckRanges
|
||||
}
|
||||
largest := smallest - gap - 2
|
||||
|
||||
ab, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
ackBlock := protocol.PacketNumber(ab)
|
||||
|
||||
if ackBlock > largest {
|
||||
return nil, errInvalidAckRanges
|
||||
return errInvalidAckRanges
|
||||
}
|
||||
smallest = largest - ackBlock
|
||||
frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largest})
|
||||
}
|
||||
|
||||
if !frame.validateAckRanges() {
|
||||
return nil, errInvalidAckRanges
|
||||
return errInvalidAckRanges
|
||||
}
|
||||
|
||||
// parse (and skip) the ECN section
|
||||
if ecn {
|
||||
for i := 0; i < 3; i++ {
|
||||
if _, err := quicvarint.Read(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ect0, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frame.ECT0 = ect0
|
||||
ect1, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frame.ECT1 = ect1
|
||||
ecnce, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
frame.ECNCE = ecnce
|
||||
}
|
||||
|
||||
return frame, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Append appends an ACK frame.
|
||||
@@ -242,6 +249,18 @@ func (f *AckFrame) AcksPacket(p protocol.PacketNumber) bool {
|
||||
return p <= f.AckRanges[i].Largest
|
||||
}
|
||||
|
||||
func (f *AckFrame) Reset() {
|
||||
f.DelayTime = 0
|
||||
f.ECT0 = 0
|
||||
f.ECT1 = 0
|
||||
f.ECNCE = 0
|
||||
for _, r := range f.AckRanges {
|
||||
r.Largest = 0
|
||||
r.Smallest = 0
|
||||
}
|
||||
f.AckRanges = f.AckRanges[:0]
|
||||
}
|
||||
|
||||
func encodeAckDelay(delay time.Duration) uint64 {
|
||||
return uint64(delay.Nanoseconds() / (1000 * (1 << protocol.AckDelayExponent)))
|
||||
}
|
||||
|
||||
24
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame_pool.go
generated
vendored
24
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame_pool.go
generated
vendored
@@ -1,24 +0,0 @@
|
||||
package wire
|
||||
|
||||
import "sync"
|
||||
|
||||
var ackFramePool = sync.Pool{New: func() any {
|
||||
return &AckFrame{}
|
||||
}}
|
||||
|
||||
func GetAckFrame() *AckFrame {
|
||||
f := ackFramePool.Get().(*AckFrame)
|
||||
f.AckRanges = f.AckRanges[:0]
|
||||
f.ECNCE = 0
|
||||
f.ECT0 = 0
|
||||
f.ECT1 = 0
|
||||
f.DelayTime = 0
|
||||
return f
|
||||
}
|
||||
|
||||
func PutAckFrame(f *AckFrame) {
|
||||
if cap(f.AckRanges) > 4 {
|
||||
return
|
||||
}
|
||||
ackFramePool.Put(f)
|
||||
}
|
||||
6
vendor/github.com/quic-go/quic-go/internal/wire/datagram_frame.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/wire/datagram_frame.go
generated
vendored
@@ -8,6 +8,12 @@ import (
|
||||
"github.com/quic-go/quic-go/quicvarint"
|
||||
)
|
||||
|
||||
// MaxDatagramSize is the maximum size of a DATAGRAM frame (RFC 9221).
|
||||
// By setting it to a large value, we allow all datagrams that fit into a QUIC packet.
|
||||
// The value is chosen such that it can still be encoded as a 2 byte varint.
|
||||
// This is a var and not a const so it can be set in tests.
|
||||
var MaxDatagramSize protocol.ByteCount = 16383
|
||||
|
||||
// A DatagramFrame is a DATAGRAM frame
|
||||
type DatagramFrame struct {
|
||||
DataLenPresent bool
|
||||
|
||||
12
vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go
generated
vendored
12
vendor/github.com/quic-go/quic-go/internal/wire/frame_parser.go
generated
vendored
@@ -39,9 +39,12 @@ const (
|
||||
type frameParser struct {
|
||||
r bytes.Reader // cached bytes.Reader, so we don't have to repeatedly allocate them
|
||||
|
||||
ackDelayExponent uint8
|
||||
|
||||
ackDelayExponent uint8
|
||||
supportsDatagrams bool
|
||||
|
||||
// To avoid allocating when parsing, keep a single ACK frame struct.
|
||||
// It is used over and over again.
|
||||
ackFrame *AckFrame
|
||||
}
|
||||
|
||||
var _ FrameParser = &frameParser{}
|
||||
@@ -51,6 +54,7 @@ func NewFrameParser(supportsDatagrams bool) *frameParser {
|
||||
return &frameParser{
|
||||
r: *bytes.NewReader(nil),
|
||||
supportsDatagrams: supportsDatagrams,
|
||||
ackFrame: &AckFrame{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +109,9 @@ func (p *frameParser) parseFrame(r *bytes.Reader, typ uint64, encLevel protocol.
|
||||
if encLevel != protocol.Encryption1RTT {
|
||||
ackDelayExponent = protocol.DefaultAckDelayExponent
|
||||
}
|
||||
frame, err = parseAckFrame(r, typ, ackDelayExponent, v)
|
||||
p.ackFrame.Reset()
|
||||
err = parseAckFrame(p.ackFrame, r, typ, ackDelayExponent, v)
|
||||
frame = p.ackFrame
|
||||
case resetStreamFrameType:
|
||||
frame, err = parseResetStreamFrame(r, v)
|
||||
case stopSendingFrameType:
|
||||
|
||||
8
vendor/github.com/quic-go/quic-go/internal/wire/header.go
generated
vendored
8
vendor/github.com/quic-go/quic-go/internal/wire/header.go
generated
vendored
@@ -13,8 +13,6 @@ import (
|
||||
)
|
||||
|
||||
// ParseConnectionID parses the destination connection ID of a packet.
|
||||
// It uses the data slice for the connection ID.
|
||||
// That means that the connection ID must not be used after the packet buffer is released.
|
||||
func ParseConnectionID(data []byte, shortHeaderConnIDLen int) (protocol.ConnectionID, error) {
|
||||
if len(data) == 0 {
|
||||
return protocol.ConnectionID{}, io.EOF
|
||||
@@ -76,6 +74,10 @@ func parseArbitraryLenConnectionIDs(r *bytes.Reader) (dest, src protocol.Arbitra
|
||||
return destConnID, srcConnID, nil
|
||||
}
|
||||
|
||||
func IsPotentialQUICPacket(firstByte byte) bool {
|
||||
return firstByte&0x40 > 0
|
||||
}
|
||||
|
||||
// IsLongHeaderPacket says if this is a Long Header packet
|
||||
func IsLongHeaderPacket(firstByte byte) bool {
|
||||
return firstByte&0x80 > 0
|
||||
@@ -110,7 +112,7 @@ func Is0RTTPacket(b []byte) bool {
|
||||
version := protocol.VersionNumber(binary.BigEndian.Uint32(b[1:5]))
|
||||
//nolint:exhaustive // We only need to test QUIC versions that we support.
|
||||
switch version {
|
||||
case protocol.Version1, protocol.VersionDraft29:
|
||||
case protocol.Version1:
|
||||
return b[0]>>4&0b11 == 0b01
|
||||
case protocol.Version2:
|
||||
return b[0]>>4&0b11 == 0b10
|
||||
|
||||
4
vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go
generated
vendored
4
vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go
generated
vendored
@@ -2,6 +2,7 @@ package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
@@ -34,6 +35,9 @@ func parseNewConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewC
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if connIDLen == 0 {
|
||||
return nil, errors.New("invalid zero-length connection ID")
|
||||
}
|
||||
connID, err := protocol.ReadConnectionID(r, int(connIDLen))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user