Bläddra i källkod

Import cloudflare tls

世界 3 år sedan
förälder
incheckning
a3bb9c2877

+ 4 - 0
.golangci.yml

@@ -7,6 +7,10 @@ linters:
     - staticcheck
     - paralleltest
 
+run:
+  skip-dirs:
+    - transport/cloudflaretls
+
 linters-settings:
 #  gci:
 #    sections:

+ 1 - 0
go.mod

@@ -4,6 +4,7 @@ go 1.18
 
 require (
 	berty.tech/go-libtor v1.0.385
+	github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc
 	github.com/cretz/bine v0.2.0
 	github.com/database64128/tfo-go v1.1.2
 	github.com/dustin/go-humanize v1.0.0

+ 2 - 0
go.sum

@@ -10,6 +10,8 @@ github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLj
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc h1:307gdRLiZ08dwOIKwc5lAQ19DRFaQQvdhHalyB4Asx8=
+github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=

+ 7 - 0
transport/cloudflaretls/README.md

@@ -0,0 +1,7 @@
+# cloudflare-tls
+
+kanged from https://github.com/cloudflare/go
+branch: cf
+commit: 4d2a840e50d2b4316aa19934271832d080c44f7f
+go: 1.18.5
+changes: use github.com/cloudflare/circl 4cf0150356fc62a0ea5c0eec2f64b756cb404145

+ 101 - 0
transport/cloudflaretls/alert.go

@@ -0,0 +1,101 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import "strconv"
+
+type alert uint8
+
+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
+	alertECHRequired                  alert = 121
+)
+
+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",
+	alertECHRequired:                  "ECH required",
+}
+
+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()
+}

+ 345 - 0
transport/cloudflaretls/auth.go

@@ -0,0 +1,345 @@
+// 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 tls
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/elliptic"
+	"crypto/rsa"
+	"errors"
+	"fmt"
+	"hash"
+	"io"
+
+	circlPki "github.com/cloudflare/circl/pki"
+	circlSign "github.com/cloudflare/circl/sign"
+)
+
+// 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:
+		scheme := circlSchemeBySigType(sigType)
+		if scheme == nil {
+			return errors.New("internal error: unknown signature type")
+		}
+		pubKey, ok := pubkey.(circlSign.PublicKey)
+		if !ok {
+			return fmt.Errorf("expected a %s public key, got %T", scheme.Name(), pubkey)
+		}
+		if !scheme.Verify(pubKey, signed, sig, nil) {
+			return fmt.Errorf("%s verification failure", scheme.Name())
+		}
+	}
+	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:
+		scheme := circlPki.SchemeByTLSID(uint(signatureAlgorithm))
+		if scheme == nil {
+			return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
+		}
+		sigType = sigTypeByCirclScheme(scheme)
+		if sigType == 0 {
+			return 0, 0, fmt.Errorf("github.com/cloudflare/circl scheme %s not supported",
+				scheme.Name())
+		}
+	}
+	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:
+		scheme := circlPki.SchemeByTLSID(uint(signatureAlgorithm))
+		if scheme == nil {
+			return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
+		}
+		hash = directSigning
+	}
+	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")
+	case circlSign.PublicKey:
+		return 0, 0, fmt.Errorf("tls: circl 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.
+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}
+	case circlSign.PublicKey:
+		scheme := pub.Scheme()
+		tlsScheme, ok := scheme.(circlPki.TLSScheme)
+		if !ok {
+			return nil
+		}
+		sigAlgs = []SignatureScheme{SignatureScheme(tlsScheme.TLSIdentifier())}
+	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
+}
+
+// selectSignatureSchemeDC picks a SignatureScheme from the peer's preference list
+// that works with the selected delegated credential. It's only called for protocol
+// versions that support delegated credential, so TLS 1.3.
+func selectSignatureSchemeDC(vers uint16, dc *DelegatedCredential, peerAlgs []SignatureScheme, peerAlgsDC []SignatureScheme) (SignatureScheme, error) {
+	if vers != VersionTLS13 {
+		return 0, errors.New("unsupported TLS version for dc")
+	}
+
+	if !isSupportedSignatureAlgorithm(dc.algorithm, peerAlgs) {
+		return undefinedSignatureScheme, errors.New("tls: peer doesn't support the delegated credential's signature")
+	}
+
+	// Pick signature scheme in the peer's preference order, as our
+	// preference order is not configurable.
+	for _, preferredAlg := range peerAlgsDC {
+		if preferredAlg == dc.cred.expCertVerfAlgo {
+			return preferredAlg, nil
+		}
+	}
+	return 0, errors.New("tls: peer doesn't support the delegated credential's signature algorithm")
+}
+
+// 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 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)
+}

+ 104 - 0
transport/cloudflaretls/cfkem.go

@@ -0,0 +1,104 @@
+// Copyright 2022 Cloudflare, Inc. All rights reserved. Use of this source code
+// is governed by a BSD-style license that can be found in the LICENSE file.
+//
+// Glue to add Circl's (post-quantum) hybrid KEMs.
+//
+// To enable set CurvePreferences with the desired scheme as the first element:
+//
+//   import (
+//      "github.com/cloudflare/circl/kem/tls"
+//      "github.com/cloudflare/circl/kem/hybrid"
+//
+//          [...]
+//
+//   config.CurvePreferences = []tls.CurveID{
+//      hybrid.X25519Kyber512Draft00().(tls.TLSScheme).TLSCurveID(),
+//      tls.X25519,
+//      tls.P256,
+//   }
+
+package tls
+
+import (
+	"fmt"
+	"io"
+
+	"github.com/cloudflare/circl/kem"
+	"github.com/cloudflare/circl/kem/hybrid"
+)
+
+// Either ecdheParameters or kem.PrivateKey
+type clientKeySharePrivate interface{}
+
+var (
+	X25519Kyber512Draft00 = CurveID(0xfe30)
+	X25519Kyber768Draft00 = CurveID(0xfe31)
+	invalidCurveID        = CurveID(0)
+)
+
+func kemSchemeKeyToCurveID(s kem.Scheme) CurveID {
+	switch s.Name() {
+	case "Kyber512-X25519":
+		return X25519Kyber512Draft00
+	case "Kyber768-X25519":
+		return X25519Kyber768Draft00
+	default:
+		return invalidCurveID
+	}
+}
+
+// Extract CurveID from clientKeySharePrivate
+func clientKeySharePrivateCurveID(ks clientKeySharePrivate) CurveID {
+	switch v := ks.(type) {
+	case kem.PrivateKey:
+		ret := kemSchemeKeyToCurveID(v.Scheme())
+		if ret == invalidCurveID {
+			panic("cfkem: internal error: don't know CurveID for this KEM")
+		}
+		return ret
+	case ecdheParameters:
+		return v.CurveID()
+	default:
+		panic("cfkem: internal error: unknown clientKeySharePrivate")
+	}
+}
+
+// Returns scheme by CurveID if supported by Circl
+func curveIdToCirclScheme(id CurveID) kem.Scheme {
+	switch id {
+	case X25519Kyber512Draft00:
+		return hybrid.Kyber512X25519()
+	case X25519Kyber768Draft00:
+		return hybrid.Kyber768X25519()
+	}
+	return nil
+}
+
+// Generate a new shared secret and encapsulates it for the packed
+// public key in ppk using randomness from rnd.
+func encapsulateForKem(scheme kem.Scheme, rnd io.Reader, ppk []byte) (
+	ct, ss []byte, alert alert, err error,
+) {
+	pk, err := scheme.UnmarshalBinaryPublicKey(ppk)
+	if err != nil {
+		return nil, nil, alertIllegalParameter, fmt.Errorf("unpack pk: %w", err)
+	}
+	seed := make([]byte, scheme.EncapsulationSeedSize())
+	if _, err := io.ReadFull(rnd, seed); err != nil {
+		return nil, nil, alertInternalError, fmt.Errorf("random: %w", err)
+	}
+	ct, ss, err = scheme.EncapsulateDeterministically(pk, seed)
+	return ct, ss, alertIllegalParameter, err
+}
+
+// Generate a new keypair using randomness from rnd.
+func generateKemKeyPair(scheme kem.Scheme, rnd io.Reader) (
+	kem.PublicKey, kem.PrivateKey, error,
+) {
+	seed := make([]byte, scheme.SeedSize())
+	if _, err := io.ReadFull(rnd, seed); err != nil {
+		return nil, nil, err
+	}
+	pk, sk := scheme.DeriveKeyPair(seed)
+	return pk, sk, nil
+}

+ 688 - 0
transport/cloudflaretls/cipher_suites.go

@@ -0,0 +1,688 @@
+// 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 tls
+
+import (
+	"crypto"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/des"
+	"crypto/hmac"
+	"crypto/rc4"
+	"crypto/sha1"
+	"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
+// 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
+}
+
+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 (
+	hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
+	hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
+	// Keep in sync with crypto/aes/cipher_s390x.go.
+	hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR &&
+		(cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
+
+	hasAESGCMHardwareSupport = runtime.GOARCH == "amd64" && hasGCMAsmAMD64 ||
+		runtime.GOARCH == "arm64" && hasGCMAsmARM64 ||
+		runtime.GOARCH == "s390x" && hasGCMAsmS390X
+)
+
+var aesgcmCiphers = map[uint16]bool{
+	// TLS 1.2
+	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:   true,
+	TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:   true,
+	TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true,
+	TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true,
+	// TLS 1.3
+	TLS_AES_128_GCM_SHA256: true,
+	TLS_AES_256_GCM_SHA384: true,
+}
+
+var nonAESGCMAEADCiphers = map[uint16]bool{
+	// TLS 1.2
+	TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:   true,
+	TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: true,
+	// TLS 1.3
+	TLS_CHACHA20_POLY1305_SHA256: true,
+}
+
+// aesgcmPreferred returns whether the first known cipher in the preference list
+// is an AES-GCM cipher, implying the peer has hardware support for it.
+func aesgcmPreferred(ciphers []uint16) bool {
+	for _, cID := range ciphers {
+		if c := cipherSuiteByID(cID); c != nil {
+			return aesgcmCiphers[cID]
+		}
+		if c := cipherSuiteTLS13ByID(cID); c != nil {
+			return aesgcmCiphers[cID]
+		}
+	}
+	return false
+}
+
+func cipherRC4(key, iv []byte, isRead bool) 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 {
+	return hmac.New(newConstantTimeHash(sha1.New), 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)
+	}
+	aead, err := cipher.NewGCM(aes)
+	if err != nil {
+		panic(err)
+	}
+
+	ret := &prefixNonceAEAD{aead: aead}
+	copy(ret.nonce[:], noncePrefix)
+	return ret
+}
+
+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
+)

+ 1666 - 0
transport/cloudflaretls/common.go

@@ -0,0 +1,1666 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"bytes"
+	"container/list"
+	"context"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/sha512"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"strings"
+	"sync"
+	"time"
+)
+
+const (
+	VersionTLS10 = 0x0301
+	VersionTLS11 = 0x0302
+	VersionTLS12 = 0x0303
+	VersionTLS13 = 0x0304
+
+	// Deprecated: SSLv3 is cryptographically broken, and is no longer
+	// supported by this package. See golang.org/issue/32716.
+	VersionSSL30 = 0x0300
+)
+
+const (
+	maxPlaintext       = 16384        // maximum plaintext payload length
+	maxCiphertext      = 16384 + 2048 // maximum ciphertext payload length
+	maxCiphertextTLS13 = 16384 + 256  // maximum ciphertext length in TLS 1.3
+	recordHeaderLen    = 5            // record header length
+	maxHandshake       = 65536        // maximum handshake we support (protocol max is 16 MB)
+	maxUselessRecords  = 16           // maximum number of consecutive non-advancing records
+)
+
+// TLS record types.
+type recordType uint8
+
+const (
+	recordTypeChangeCipherSpec recordType = 20
+	recordTypeAlert            recordType = 21
+	recordTypeHandshake        recordType = 22
+	recordTypeApplicationData  recordType = 23
+)
+
+// TLS handshake message types.
+const (
+	typeHelloRequest        uint8 = 0
+	typeClientHello         uint8 = 1
+	typeServerHello         uint8 = 2
+	typeNewSessionTicket    uint8 = 4
+	typeEndOfEarlyData      uint8 = 5
+	typeEncryptedExtensions uint8 = 8
+	typeCertificate         uint8 = 11
+	typeServerKeyExchange   uint8 = 12
+	typeCertificateRequest  uint8 = 13
+	typeServerHelloDone     uint8 = 14
+	typeCertificateVerify   uint8 = 15
+	typeClientKeyExchange   uint8 = 16
+	typeFinished            uint8 = 20
+	typeCertificateStatus   uint8 = 22
+	typeKeyUpdate           uint8 = 24
+	typeNextProtocol        uint8 = 67  // Not IANA assigned
+	typeMessageHash         uint8 = 254 // synthetic message
+)
+
+// TLS compression types.
+const (
+	compressionNone uint8 = 0
+)
+
+// TLS extension numbers
+const (
+	extensionServerName              uint16 = 0
+	extensionStatusRequest           uint16 = 5
+	extensionSupportedCurves         uint16 = 10 // supported_groups in TLS 1.3, see RFC 8446, Section 4.2.7
+	extensionSupportedPoints         uint16 = 11
+	extensionSignatureAlgorithms     uint16 = 13
+	extensionALPN                    uint16 = 16
+	extensionSCT                     uint16 = 18
+	extensionDelegatedCredentials    uint16 = 34
+	extensionSessionTicket           uint16 = 35
+	extensionPreSharedKey            uint16 = 41
+	extensionEarlyData               uint16 = 42
+	extensionSupportedVersions       uint16 = 43
+	extensionCookie                  uint16 = 44
+	extensionPSKModes                uint16 = 45
+	extensionCertificateAuthorities  uint16 = 47
+	extensionSignatureAlgorithmsCert uint16 = 50
+	extensionKeyShare                uint16 = 51
+	extensionRenegotiationInfo       uint16 = 0xff01
+	extensionECH                     uint16 = 0xfe0d // draft-ietf-tls-esni-13
+	extensionECHOuterExtensions      uint16 = 0xfd00 // draft-ietf-tls-esni-13
+)
+
+// TLS signaling cipher suite values
+const (
+	scsvRenegotiation uint16 = 0x00ff
+)
+
+// CurveID is the type of a TLS identifier for an elliptic curve. See
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8.
+//
+// In TLS 1.3, this type is called NamedGroup, but at this time this library
+// only supports Elliptic Curve based groups. See RFC 8446, Section 4.2.7.
+type CurveID uint16
+
+const (
+	CurveP256 CurveID = 23
+	CurveP384 CurveID = 24
+	CurveP521 CurveID = 25
+	X25519    CurveID = 29
+)
+
+// TLS 1.3 Key Share. See RFC 8446, Section 4.2.8.
+type keyShare struct {
+	group CurveID
+	data  []byte
+}
+
+// TLS 1.3 PSK Key Exchange Modes. See RFC 8446, Section 4.2.9.
+const (
+	pskModePlain uint8 = 0
+	pskModeDHE   uint8 = 1
+)
+
+// TLS 1.3 PSK Identity. Can be a Session Ticket, or a reference to a saved
+// session. See RFC 8446, Section 4.2.11.
+type pskIdentity struct {
+	label               []byte
+	obfuscatedTicketAge uint32
+}
+
+// TLS Elliptic Curve Point Formats
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
+const (
+	pointFormatUncompressed uint8 = 0
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+	statusTypeOCSP uint8 = 1
+)
+
+// Certificate types (for certificateRequestMsg)
+const (
+	certTypeRSASign   = 1
+	certTypeECDSASign = 64 // ECDSA or EdDSA keys, see RFC 8422, Section 3.
+)
+
+// Signature algorithms (for internal signaling use). Starting at 225 to avoid overlap with
+// TLS 1.2 codepoints (RFC 5246, Appendix A.4.1), with which these have nothing to do.
+const (
+	signaturePKCS1v15 uint8 = iota + 225
+	signatureRSAPSS
+	signatureECDSA
+	signatureEd25519
+	signatureEdDilithium3
+)
+
+// directSigning is a standard Hash value that signals that no pre-hashing
+// should be performed, and that the input should be signed directly. It is the
+// hash function associated with the Ed25519 signature scheme.
+var directSigning crypto.Hash = 0
+
+// supportedSignatureAlgorithms contains the signature and hash algorithms that
+// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+
+// CertificateRequest. The two fields are merged to match with TLS 1.3.
+// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc.
+var supportedSignatureAlgorithms = []SignatureScheme{
+	PSSWithSHA256,
+	ECDSAWithP256AndSHA256,
+	Ed25519,
+	PSSWithSHA384,
+	PSSWithSHA512,
+	PKCS1WithSHA256,
+	PKCS1WithSHA384,
+	PKCS1WithSHA512,
+	ECDSAWithP384AndSHA384,
+	ECDSAWithP521AndSHA512,
+	PKCS1WithSHA1,
+	ECDSAWithSHA1,
+}
+
+// supportedSignatureAlgorithmsDC contains the signature and hash algorithms that
+// the code advertises as supported in a TLS 1.3 ClientHello and in a TLS 1.3
+// CertificateRequest. This excludes 'rsa_pss_rsae_' algorithms.
+var supportedSignatureAlgorithmsDC = []SignatureScheme{
+	ECDSAWithP256AndSHA256,
+	Ed25519,
+	ECDSAWithP384AndSHA384,
+	ECDSAWithP521AndSHA512,
+}
+
+// helloRetryRequestRandom is set as the Random value of a ServerHello
+// to signal that the message is actually a HelloRetryRequest.
+var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3.
+	0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
+	0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
+	0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
+	0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C,
+}
+
+const (
+	// downgradeCanaryTLS12 or downgradeCanaryTLS11 is embedded in the server
+	// random as a downgrade protection if the server would be capable of
+	// negotiating a higher version. See RFC 8446, Section 4.1.3.
+	downgradeCanaryTLS12 = "DOWNGRD\x01"
+	downgradeCanaryTLS11 = "DOWNGRD\x00"
+)
+
+// testingOnlyForceDowngradeCanary is set in tests to force the server side to
+// include downgrade canaries even if it's using its highers supported version.
+var testingOnlyForceDowngradeCanary bool
+
+// testingTriggerHRR causes the server to intentionally trigger a
+// HelloRetryRequest (HRR). This is useful for testing new TLS features that
+// change the HRR codepath.
+var testingTriggerHRR bool
+
+// testingECHTriggerBypassAfterHRR causes the client to bypass ECH after HRR.
+// If available, the client will offer ECH in the first CH only.
+var testingECHTriggerBypassAfterHRR bool
+
+// testingECHTriggerBypassBeforeHRR causes the client to bypass ECH before HRR.
+// The client will offer ECH in the second CH only.
+var testingECHTriggerBypassBeforeHRR bool
+
+// testingECHIllegalHandleAfterHRR causes the client to illegally change the ECH
+// extension after HRR.
+var testingECHIllegalHandleAfterHRR bool
+
+// testingECHTriggerPayloadDecryptError causes the client to to send an
+// inauthentic payload.
+var testingECHTriggerPayloadDecryptError bool
+
+// testingECHOuterExtMany causes a client to incorporate a sequence of
+// outer extensions into the ClientHelloInner when it offers the ECH extension.
+// The "key_share" extension is the only incorporated extension by default.
+var testingECHOuterExtMany bool
+
+// testingECHOuterExtNone causes a client to not use the "outer_extension"
+// mechanism for ECH. The "key_shares" extension is incorporated by default.
+var testingECHOuterExtNone bool
+
+// testingECHOuterExtIncorrectOrder causes the client to send the
+// "outer_extension" extension in the wrong order when offering the ECH
+// extension.
+var testingECHOuterExtIncorrectOrder bool
+
+// testingECHOuterExtIllegal causes the client to send in its
+// "outer_extension" extension the codepoint for the ECH extension.
+var testingECHOuterExtIllegal bool
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState struct {
+	// Version is the TLS version used by the connection (e.g. VersionTLS12).
+	Version uint16
+
+	// HandshakeComplete is true if the handshake has concluded.
+	HandshakeComplete bool
+
+	// DidResume is true if this connection was successfully resumed from a
+	// previous session with a session ticket or similar mechanism.
+	DidResume bool
+
+	// CipherSuite is the cipher suite negotiated for the connection (e.g.
+	// TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256).
+	CipherSuite uint16
+
+	// NegotiatedProtocol is the application protocol negotiated with ALPN.
+	NegotiatedProtocol string
+
+	// NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation.
+	//
+	// Deprecated: this value is always true.
+	NegotiatedProtocolIsMutual bool
+
+	// ServerName is the value of the Server Name Indication extension sent by
+	// the client. It's available both on the server and on the client side.
+	ServerName string
+
+	// PeerCertificates are the parsed certificates sent by the peer, in the
+	// order in which they were sent. The first element is the leaf certificate
+	// that the connection is verified against.
+	//
+	// On the client side, it can't be empty. On the server side, it can be
+	// empty if Config.ClientAuth is not RequireAnyClientCert or
+	// RequireAndVerifyClientCert.
+	PeerCertificates []*x509.Certificate
+
+	// VerifiedChains is a list of one or more chains where the first element is
+	// PeerCertificates[0] and the last element is from Config.RootCAs (on the
+	// client side) or Config.ClientCAs (on the server side).
+	//
+	// On the client side, it's set if Config.InsecureSkipVerify is false. On
+	// the server side, it's set if Config.ClientAuth is VerifyClientCertIfGiven
+	// (and the peer provided a certificate) or RequireAndVerifyClientCert.
+	VerifiedChains [][]*x509.Certificate
+
+	// VerifiedDC indicates that the Delegated Credential sent by the peer (if advertised
+	// and correctly processed), which has been verified against the leaf certificate,
+	// has been used.
+	VerifiedDC bool
+
+	// SignedCertificateTimestamps is a list of SCTs provided by the peer
+	// through the TLS handshake for the leaf certificate, if any.
+	SignedCertificateTimestamps [][]byte
+
+	// OCSPResponse is a stapled Online Certificate Status Protocol (OCSP)
+	// response provided by the peer for the leaf certificate, if any.
+	OCSPResponse []byte
+
+	// TLSUnique contains the "tls-unique" channel binding value (see RFC 5929,
+	// Section 3). This value will be nil for TLS 1.3 connections and for all
+	// resumed connections.
+	//
+	// Deprecated: there are conditions in which this value might not be unique
+	// to a connection. See the Security Considerations sections of RFC 5705 and
+	// RFC 7627, and https://mitls.org/pages/attacks/3SHAKE#channelbindings.
+	TLSUnique []byte
+
+	// ECHAccepted is set if the ECH extension was offered by the client and
+	// accepted by the server.
+	ECHAccepted bool
+
+	// ECHOffered is set if the ECH extension is present in the ClientHello.
+	// This means the client has offered ECH or sent GREASE ECH.
+	ECHOffered bool
+
+	// CFControl is used to pass additional TLS configuration information to
+	// HTTP requests.
+	//
+	// NOTE: This feature is used to implement Cloudflare-internal features.
+	// This feature is unstable and applications MUST NOT depend on it.
+	CFControl interface{}
+
+	// ekm is a closure exposed via ExportKeyingMaterial.
+	ekm func(label string, context []byte, length int) ([]byte, error)
+}
+
+// ExportKeyingMaterial returns length bytes of exported key material in a new
+// slice as defined in RFC 5705. If context is nil, it is not used as part of
+// the seed. If the connection was set to allow renegotiation via
+// Config.Renegotiation, this function will return an error.
+func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
+	return cs.ekm(label, context, length)
+}
+
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+const (
+	// NoClientCert indicates that no client certificate should be requested
+	// during the handshake, and if any certificates are sent they will not
+	// be verified.
+	NoClientCert ClientAuthType = iota
+	// RequestClientCert indicates that a client certificate should be requested
+	// during the handshake, but does not require that the client send any
+	// certificates.
+	RequestClientCert
+	// RequireAnyClientCert indicates that a client certificate should be requested
+	// during the handshake, and that at least one certificate is required to be
+	// sent by the client, but that certificate is not required to be valid.
+	RequireAnyClientCert
+	// VerifyClientCertIfGiven indicates that a client certificate should be requested
+	// during the handshake, but does not require that the client sends a
+	// certificate. If the client does send a certificate it is required to be
+	// valid.
+	VerifyClientCertIfGiven
+	// RequireAndVerifyClientCert indicates that a client certificate should be requested
+	// during the handshake, and that at least one valid certificate is required
+	// to be sent by the client.
+	RequireAndVerifyClientCert
+)
+
+// requiresClientCert reports whether the ClientAuthType requires a client
+// certificate to be provided.
+func requiresClientCert(c ClientAuthType) bool {
+	switch c {
+	case RequireAnyClientCert, RequireAndVerifyClientCert:
+		return true
+	default:
+		return false
+	}
+}
+
+// ClientSessionState contains the state needed by clients to resume TLS
+// sessions.
+type ClientSessionState struct {
+	sessionTicket      []uint8               // Encrypted ticket used for session resumption with server
+	vers               uint16                // TLS version negotiated for the session
+	cipherSuite        uint16                // Ciphersuite negotiated for the session
+	masterSecret       []byte                // Full handshake MasterSecret, or TLS 1.3 resumption_master_secret
+	serverCertificates []*x509.Certificate   // Certificate chain presented by the server
+	verifiedChains     [][]*x509.Certificate // Certificate chains we built for verification
+	receivedAt         time.Time             // When the session ticket was received from the server
+	ocspResponse       []byte                // Stapled OCSP response presented by the server
+	scts               [][]byte              // SCTs presented by the server
+
+	// TLS 1.3 fields.
+	nonce  []byte    // Ticket nonce sent by the server, to derive PSK
+	useBy  time.Time // Expiration of the ticket lifetime as set by the server
+	ageAdd uint32    // Random obfuscation factor for sending the ticket age
+}
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// 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.
+type ClientSessionCache interface {
+	// Get searches for a ClientSessionState associated with the given key.
+	// On return, ok is true if one was found.
+	Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+	// Put adds the ClientSessionState to the cache with the given key. It might
+	// get called multiple times in a connection if a TLS 1.3 server provides
+	// more than one session ticket. If called with a nil *ClientSessionState,
+	// it should remove the cache entry.
+	Put(sessionKey string, cs *ClientSessionState)
+}
+
+//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go
+
+// SignatureScheme identifies a signature algorithm supported by TLS. See
+// RFC 8446, Section 4.2.3.
+type SignatureScheme uint16
+
+const (
+	// RSASSA-PKCS1-v1_5 algorithms.
+	PKCS1WithSHA256 SignatureScheme = 0x0401
+	PKCS1WithSHA384 SignatureScheme = 0x0501
+	PKCS1WithSHA512 SignatureScheme = 0x0601
+
+	// RSASSA-PSS algorithms with public key OID rsaEncryption.
+	PSSWithSHA256 SignatureScheme = 0x0804
+	PSSWithSHA384 SignatureScheme = 0x0805
+	PSSWithSHA512 SignatureScheme = 0x0806
+
+	// ECDSA algorithms. Only constrained to a specific curve in TLS 1.3.
+	ECDSAWithP256AndSHA256 SignatureScheme = 0x0403
+	ECDSAWithP384AndSHA384 SignatureScheme = 0x0503
+	ECDSAWithP521AndSHA512 SignatureScheme = 0x0603
+
+	// EdDSA algorithms.
+	Ed25519 SignatureScheme = 0x0807
+
+	// Legacy signature and hash algorithms for TLS 1.2.
+	PKCS1WithSHA1 SignatureScheme = 0x0201
+	ECDSAWithSHA1 SignatureScheme = 0x0203
+)
+
+// ClientHelloInfo contains information from a ClientHello message in order to
+// guide application logic in the GetCertificate and GetConfigForClient callbacks.
+type ClientHelloInfo struct {
+	// CipherSuites lists the CipherSuites supported by the client (e.g.
+	// TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
+	CipherSuites []uint16
+
+	// ServerName indicates the name of the server requested by the client
+	// in order to support virtual hosting. ServerName is only set if the
+	// client is using SNI (see RFC 4366, Section 3.1).
+	ServerName string
+
+	// SupportedCurves lists the elliptic curves supported by the client.
+	// SupportedCurves is set only if the Supported Elliptic Curves
+	// Extension is being used (see RFC 4492, Section 5.1.1).
+	SupportedCurves []CurveID
+
+	// SupportedPoints lists the point formats supported by the client.
+	// SupportedPoints is set only if the Supported Point Formats Extension
+	// is being used (see RFC 4492, Section 5.1.2).
+	SupportedPoints []uint8
+
+	// SignatureSchemes lists the signature and hash schemes that the client
+	// is willing to verify. SignatureSchemes is set only if the Signature
+	// Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
+	SignatureSchemes []SignatureScheme
+
+	// SignatureSchemesDC lists the signature schemes that the client
+	// is willing to verify when using Delegated Credentials.
+	// This is and can be different from SignatureSchemes. SignatureSchemesDC
+	// is set only if the DelegatedCredentials Extension is being used.
+	// If Delegated Credentials are supported, this list should not be nil.
+	SignatureSchemesDC []SignatureScheme
+
+	// SupportedProtos lists the application protocols supported by the client.
+	// SupportedProtos is set only if the Application-Layer Protocol
+	// Negotiation Extension is being used (see RFC 7301, Section 3.1).
+	//
+	// Servers can select a protocol by setting Config.NextProtos in a
+	// GetConfigForClient return value.
+	SupportedProtos []string
+
+	// SupportedVersions lists the TLS versions supported by the client.
+	// For TLS versions less than 1.3, this is extrapolated from the max
+	// version advertised by the client, so values other than the greatest
+	// might be rejected if used.
+	SupportedVersions []uint16
+
+	// SupportDelegatedCredential is true if the client indicated willingness
+	// to negotiate the Delegated Credential extension.
+	SupportsDelegatedCredential bool
+
+	// Conn is the underlying net.Conn for the connection. Do not read
+	// from, or write to, this connection; that will cause the TLS
+	// connection to fail.
+	Conn net.Conn
+
+	// config is embedded by the GetCertificate or GetConfigForClient caller,
+	// for use with SupportsCertificate.
+	config *Config
+
+	// ctx is the context of the handshake that is in progress.
+	ctx context.Context
+}
+
+// Context returns the context of the handshake that is in progress.
+// This context is a child of the context passed to HandshakeContext,
+// if any, and is canceled when the handshake concludes.
+func (c *ClientHelloInfo) Context() context.Context {
+	return c.ctx
+}
+
+// CertificateRequestInfo contains information from a server's
+// CertificateRequest message, which is used to demand a certificate and proof
+// of control from a client.
+type CertificateRequestInfo struct {
+	// AcceptableCAs contains zero or more, DER-encoded, X.501
+	// Distinguished Names. These are the names of root or intermediate CAs
+	// that the server wishes the returned certificate to be signed by. An
+	// empty slice indicates that the server has no preference.
+	AcceptableCAs [][]byte
+
+	// SupportDelegatedCredential is true if the server indicated willingness
+	// to negotiate the Delegated Credential extension.
+	SupportsDelegatedCredential bool
+
+	// SignatureSchemes lists the signature schemes that the server is
+	// willing to verify.
+	SignatureSchemes []SignatureScheme
+
+	// SignatureSchemesDC lists the signature schemes that the server
+	// is willing to verify when using Delegated Credentials.
+	// This is and can be different from SignatureSchemes. SignatureSchemesDC
+	// is set only if the DelegatedCredentials Extension is being used.
+	// If Delegated Credentials are supported, this list should not be nil.
+	SignatureSchemesDC []SignatureScheme
+
+	// Version is the TLS version that was negotiated for this connection.
+	Version uint16
+
+	// ctx is the context of the handshake that is in progress.
+	ctx context.Context
+}
+
+// Context returns the context of the handshake that is in progress.
+// This context is a child of the context passed to HandshakeContext,
+// if any, and is canceled when the handshake concludes.
+func (c *CertificateRequestInfo) Context() context.Context {
+	return c.ctx
+}
+
+// RenegotiationSupport enumerates the different levels of support for TLS
+// renegotiation. TLS renegotiation is the act of performing subsequent
+// handshakes on a connection after the first. This significantly complicates
+// the state machine and has been the source of numerous, subtle security
+// issues. Initiating a renegotiation is not supported, but support for
+// accepting renegotiation requests may be enabled.
+//
+// Even when enabled, the server may not change its identity between handshakes
+// (i.e. the leaf certificate must be the same). Additionally, concurrent
+// handshake and application data flow is not permitted so renegotiation can
+// only be used with protocols that synchronise with the renegotiation, such as
+// HTTPS.
+//
+// Renegotiation is not defined in TLS 1.3.
+type RenegotiationSupport int
+
+const (
+	// RenegotiateNever disables renegotiation.
+	RenegotiateNever RenegotiationSupport = iota
+
+	// RenegotiateOnceAsClient allows a remote server to request
+	// renegotiation once per connection.
+	RenegotiateOnceAsClient
+
+	// RenegotiateFreelyAsClient allows a remote server to repeatedly
+	// request renegotiation.
+	RenegotiateFreelyAsClient
+)
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
+type Config struct {
+	// Rand provides the source of entropy for nonces and RSA blinding.
+	// If Rand is nil, TLS uses the cryptographic random reader in package
+	// crypto/rand.
+	// The Reader must be safe for use by multiple goroutines.
+	Rand io.Reader
+
+	// Time returns the current time as the number of seconds since the epoch.
+	// If Time is nil, TLS uses time.Now.
+	Time func() time.Time
+
+	// Certificates contains one or more certificate chains to present to the
+	// other side of the connection. The first certificate compatible with the
+	// peer's requirements is selected automatically.
+	//
+	// Server configurations must set one of Certificates, GetCertificate or
+	// GetConfigForClient. Clients doing client-authentication may set either
+	// Certificates or GetClientCertificate.
+	//
+	// Note: if there are multiple Certificates, and they don't have the
+	// optional field Leaf set, certificate selection will incur a significant
+	// per-handshake performance cost.
+	Certificates []Certificate
+
+	// NameToCertificate maps from a certificate name to an element of
+	// Certificates. Note that a certificate name can be of the form
+	// '*.example.com' and so doesn't have to be a domain name as such.
+	//
+	// Deprecated: NameToCertificate only allows associating a single
+	// certificate with a given name. Leave this field nil to let the library
+	// select the first compatible chain from Certificates.
+	NameToCertificate map[string]*Certificate
+
+	// GetCertificate returns a Certificate based on the given
+	// ClientHelloInfo. It will only be called if the client supplies SNI
+	// information or if Certificates is empty.
+	//
+	// If GetCertificate is nil or returns nil, then the certificate is
+	// retrieved from NameToCertificate. If NameToCertificate is nil, the
+	// best element of Certificates will be used.
+	GetCertificate func(*ClientHelloInfo) (*Certificate, error)
+
+	// GetClientCertificate, if not nil, is called when a server requests a
+	// certificate from a client. If set, the contents of Certificates will
+	// be ignored.
+	//
+	// If GetClientCertificate returns an error, the handshake will be
+	// aborted and that error will be returned. Otherwise
+	// GetClientCertificate must return a non-nil Certificate. If
+	// Certificate.Certificate is empty then no certificate will be sent to
+	// the server. If this is unacceptable to the server then it may abort
+	// the handshake.
+	//
+	// GetClientCertificate may be called multiple times for the same
+	// connection if renegotiation occurs or if TLS 1.3 is in use.
+	GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
+
+	// GetConfigForClient, if not nil, is called after a ClientHello is
+	// received from a client. It may return a non-nil Config in order to
+	// change the Config that will be used to handle this connection. If
+	// the returned Config is nil, the original Config will be used. The
+	// Config returned by this callback may not be subsequently modified.
+	//
+	// If GetConfigForClient is nil, the Config passed to Server() will be
+	// used for all connections.
+	//
+	// If SessionTicketKey was explicitly set on the returned Config, or if
+	// SetSessionTicketKeys was called on the returned Config, those keys will
+	// be used. Otherwise, the original Config keys will be used (and possibly
+	// rotated if they are automatically managed).
+	GetConfigForClient func(*ClientHelloInfo) (*Config, error)
+
+	// VerifyPeerCertificate, if not nil, is called after normal
+	// certificate verification by either a TLS client or server. It
+	// receives the raw ASN.1 certificates provided by the peer and also
+	// any verified chains that normal processing found. If it returns a
+	// non-nil error, the handshake is aborted and that error results.
+	//
+	// If normal verification fails then the handshake will abort before
+	// considering this callback. If normal verification is disabled by
+	// setting InsecureSkipVerify, or (for a server) when ClientAuth is
+	// RequestClientCert or RequireAnyClientCert, then this callback will
+	// be considered but the verifiedChains argument will always be nil.
+	VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
+
+	// VerifyConnection, if not nil, is called after normal certificate
+	// verification and after VerifyPeerCertificate by either a TLS client
+	// or server. If it returns a non-nil error, the handshake is aborted
+	// and that error results.
+	//
+	// If normal verification fails then the handshake will abort before
+	// considering this callback. This callback will run for all connections
+	// regardless of InsecureSkipVerify or ClientAuth settings.
+	VerifyConnection func(ConnectionState) error
+
+	// RootCAs defines the set of root certificate authorities
+	// that clients use when verifying server certificates.
+	// If RootCAs is nil, TLS uses the host's root CA set.
+	RootCAs *x509.CertPool
+
+	// NextProtos is a list of supported application level protocols, in
+	// order of preference. If both peers support ALPN, the selected
+	// protocol will be one from this list, and the connection will fail
+	// if there is no mutually supported protocol. If NextProtos is empty
+	// or the peer doesn't support ALPN, the connection will succeed and
+	// ConnectionState.NegotiatedProtocol will be empty.
+	NextProtos []string
+
+	// ServerName is used to verify the hostname on the returned
+	// certificates unless InsecureSkipVerify is given. It is also included
+	// in the client's handshake to support virtual hosting unless it is
+	// an IP address.
+	ServerName string
+
+	// ClientAuth determines the server's policy for
+	// TLS Client Authentication. The default is NoClientCert.
+	ClientAuth ClientAuthType
+
+	// ClientCAs defines the set of root certificate authorities
+	// that servers use if required to verify a client certificate
+	// by the policy in ClientAuth.
+	ClientCAs *x509.CertPool
+
+	// InsecureSkipVerify controls whether a client verifies the server's
+	// certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
+	// accepts any certificate presented by the server and any host name in that
+	// certificate. In this mode, TLS is susceptible to machine-in-the-middle
+	// attacks unless custom verification is used. This should be used only for
+	// testing or in combination with VerifyConnection or VerifyPeerCertificate.
+	InsecureSkipVerify bool
+
+	// CipherSuites is a list of enabled TLS 1.0–1.2 cipher suites. The order of
+	// the list is ignored. Note that TLS 1.3 ciphersuites are not configurable.
+	//
+	// If CipherSuites is nil, a safe default list is used. The default cipher
+	// suites might change over time.
+	CipherSuites []uint16
+
+	// PreferServerCipherSuites is a legacy field and has no effect.
+	//
+	// It used to control whether the server would follow the client's or the
+	// server's preference. Servers now select the best mutually supported
+	// cipher suite based on logic that takes into account inferred client
+	// hardware, server hardware, and security.
+	//
+	// Deprecated: PreferServerCipherSuites is ignored.
+	PreferServerCipherSuites bool
+
+	// SessionTicketsDisabled may be set to true to disable session ticket and
+	// PSK (resumption) support. Note that on clients, session ticket support is
+	// also disabled if ClientSessionCache is nil. On clients or servers,
+	// support is disabled if the ECH extension is enabled.
+	SessionTicketsDisabled bool
+
+	// SessionTicketKey is used by TLS servers to provide session resumption.
+	// See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
+	// with random data before the first server handshake.
+	//
+	// Deprecated: if this field is left at zero, session ticket keys will be
+	// automatically rotated every day and dropped after seven days. For
+	// customizing the rotation schedule or synchronizing servers that are
+	// terminating connections for the same host, use SetSessionTicketKeys.
+	SessionTicketKey [32]byte
+
+	// ClientSessionCache is a cache of ClientSessionState entries for TLS
+	// session resumption. It is only used by clients.
+	ClientSessionCache ClientSessionCache
+
+	// MinVersion contains the minimum TLS version that is acceptable.
+	//
+	// By default, TLS 1.2 is currently used as the minimum when acting as a
+	// client, and TLS 1.0 when acting as a server. TLS 1.0 is the minimum
+	// supported by this package, both as a client and as a server.
+	//
+	// The client-side default can temporarily be reverted to TLS 1.0 by
+	// including the value "x509sha1=1" in the GODEBUG environment variable.
+	// Note that this option will be removed in Go 1.19 (but it will still be
+	// possible to set this field to VersionTLS10 explicitly).
+	MinVersion uint16
+
+	// MaxVersion contains the maximum TLS version that is acceptable.
+	//
+	// By default, the maximum version supported by this package is used,
+	// which is currently TLS 1.3.
+	MaxVersion uint16
+
+	// CurvePreferences contains the elliptic curves that will be used in
+	// an ECDHE handshake, in preference order. If empty, the default will
+	// be used. The client will use the first preference as the type for
+	// its key share in TLS 1.3. This may change in the future.
+	CurvePreferences []CurveID
+
+	// PQSignatureSchemesEnabled controls whether additional post-quantum
+	// signature schemes are supported for peer certificates. For available
+	// signature schemes, see tls_cf.go.
+	PQSignatureSchemesEnabled bool
+
+	// DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
+	// When true, the largest possible TLS record size is always used. When
+	// false, the size of TLS records may be adjusted in an attempt to
+	// improve latency.
+	DynamicRecordSizingDisabled bool
+
+	// Renegotiation controls what types of renegotiation are supported.
+	// The default, none, is correct for the vast majority of applications.
+	Renegotiation RenegotiationSupport
+
+	// KeyLogWriter optionally specifies a destination for TLS master secrets
+	// in NSS key log format that can be used to allow external programs
+	// such as Wireshark to decrypt TLS connections.
+	// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+	// Use of KeyLogWriter compromises security and should only be
+	// used for debugging.
+	KeyLogWriter io.Writer
+
+	// ECHEnabled determines whether the ECH extension is enabled for this
+	// connection.
+	ECHEnabled bool
+
+	// ClientECHConfigs are the parameters used by the client when it offers the
+	// ECH extension. If ECH is enabled, a suitable configuration is found, and
+	// the client supports TLS 1.3, then it will offer ECH in this handshake.
+	// Otherwise, if ECH is enabled, it will send a dummy ECH extension.
+	ClientECHConfigs []ECHConfig
+
+	// ServerECHProvider is the ECH provider used by the client-facing server
+	// for the ECH extension. If the client offers ECH and TLS 1.3 is
+	// negotiated, then the provider is used to compute the HPKE context
+	// (draft-irtf-cfrg-hpke-07), which in turn is used to decrypt the extension
+	// payload.
+	ServerECHProvider ECHProvider
+
+	// CFEventHandler, if set, is called by the client and server at various
+	// points during the handshake to handle specific events. This is used
+	// primarily for collecting metrics.
+	//
+	// NOTE: This feature is used to implement Cloudflare-internal features.
+	// This feature is unstable and applications MUST NOT depend on it.
+	CFEventHandler func(event CFEvent)
+
+	// CFControl is used to pass additional TLS configuration information to
+	// HTTP requests via ConnectionState.
+	//
+	// NOTE: This feature is used to implement Cloudflare-internal features.
+	// This feature is unstable and applications MUST NOT depend on it.
+	CFControl interface{}
+
+	// SupportDelegatedCredential is true if the client or server is willing
+	// to negotiate the delegated credential extension.
+	// This can only be used with TLS 1.3.
+	//
+	// See https://tools.ietf.org/html/draft-ietf-tls-subcerts.
+	SupportDelegatedCredential bool
+
+	// mutex protects sessionTicketKeys and autoSessionTicketKeys.
+	mutex sync.RWMutex
+	// sessionTicketKeys contains zero or more ticket keys. If set, it means the
+	// the keys were set with SessionTicketKey or SetSessionTicketKeys. The
+	// first key is used for new tickets and any subsequent keys can be used to
+	// decrypt old tickets. The slice contents are not protected by the mutex
+	// and are immutable.
+	sessionTicketKeys []ticketKey
+	// autoSessionTicketKeys is like sessionTicketKeys but is owned by the
+	// auto-rotation logic. See Config.ticketKeys.
+	autoSessionTicketKeys []ticketKey
+}
+
+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.
+	ticketKeyNameLen = 16
+
+	// ticketKeyLifetime is how long a ticket key remains valid and can be used to
+	// resume a client connection.
+	ticketKeyLifetime = 7 * 24 * time.Hour // 7 days
+
+	// ticketKeyRotation is how often the server should rotate the session ticket key
+	// that is used for new tickets.
+	ticketKeyRotation = 24 * time.Hour
+)
+
+// ticketKey is the internal representation of a session ticket key.
+type ticketKey struct {
+	// keyName is an opaque byte string that serves to identify the session
+	// ticket key. It's exposed as plaintext in every session ticket.
+	keyName [ticketKeyNameLen]byte
+	aesKey  [16]byte
+	hmacKey [16]byte
+	// created is the time at which this ticket key was created. See Config.ticketKeys.
+	created time.Time
+}
+
+// ticketKeyFromBytes converts from the external representation of a session
+// ticket key to a ticketKey. Externally, session ticket keys are 32 random
+// bytes and this function expands that into sufficient name and key material.
+func (c *Config) ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+	hashed := sha512.Sum512(b[:])
+	copy(key.keyName[:], hashed[:ticketKeyNameLen])
+	copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
+	copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
+	key.created = c.time()
+	return key
+}
+
+// maxSessionTicketLifetime is the maximum allowed lifetime of a TLS 1.3 session
+// ticket, and the lifetime we set for tickets we send.
+const maxSessionTicketLifetime = 7 * 24 * time.Hour
+
+// Clone returns a shallow clone of c or nil if c is nil. It is safe to clone a Config that is
+// being used concurrently by a TLS client or server.
+func (c *Config) Clone() *Config {
+	if c == nil {
+		return nil
+	}
+	c.mutex.RLock()
+	defer c.mutex.RUnlock()
+	return &Config{
+		Rand:                        c.Rand,
+		Time:                        c.Time,
+		Certificates:                c.Certificates,
+		NameToCertificate:           c.NameToCertificate,
+		GetCertificate:              c.GetCertificate,
+		GetClientCertificate:        c.GetClientCertificate,
+		GetConfigForClient:          c.GetConfigForClient,
+		VerifyPeerCertificate:       c.VerifyPeerCertificate,
+		VerifyConnection:            c.VerifyConnection,
+		RootCAs:                     c.RootCAs,
+		NextProtos:                  c.NextProtos,
+		ServerName:                  c.ServerName,
+		ClientAuth:                  c.ClientAuth,
+		ClientCAs:                   c.ClientCAs,
+		InsecureSkipVerify:          c.InsecureSkipVerify,
+		CipherSuites:                c.CipherSuites,
+		PreferServerCipherSuites:    c.PreferServerCipherSuites,
+		SessionTicketsDisabled:      c.SessionTicketsDisabled,
+		SessionTicketKey:            c.SessionTicketKey,
+		ClientSessionCache:          c.ClientSessionCache,
+		MinVersion:                  c.MinVersion,
+		MaxVersion:                  c.MaxVersion,
+		CurvePreferences:            c.CurvePreferences,
+		PQSignatureSchemesEnabled:   c.PQSignatureSchemesEnabled,
+		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
+		Renegotiation:               c.Renegotiation,
+		KeyLogWriter:                c.KeyLogWriter,
+		SupportDelegatedCredential:  c.SupportDelegatedCredential,
+		ECHEnabled:                  c.ECHEnabled,
+		ClientECHConfigs:            c.ClientECHConfigs,
+		ServerECHProvider:           c.ServerECHProvider,
+		CFEventHandler:              c.CFEventHandler,
+		CFControl:                   c.CFControl,
+		sessionTicketKeys:           c.sessionTicketKeys,
+		autoSessionTicketKeys:       c.autoSessionTicketKeys,
+	}
+}
+
+// deprecatedSessionTicketKey is set as the prefix of SessionTicketKey if it was
+// randomized for backwards compatibility but is not in use.
+var deprecatedSessionTicketKey = []byte("DEPRECATED")
+
+// initLegacySessionTicketKeyRLocked ensures the legacy SessionTicketKey field is
+// randomized if empty, and that sessionTicketKeys is populated from it otherwise.
+func (c *Config) initLegacySessionTicketKeyRLocked() {
+	// Don't write if SessionTicketKey is already defined as our deprecated string,
+	// or if it is defined by the user but sessionTicketKeys is already set.
+	if c.SessionTicketKey != [32]byte{} &&
+		(bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) || len(c.sessionTicketKeys) > 0) {
+		return
+	}
+
+	// We need to write some data, so get an exclusive lock and re-check any conditions.
+	c.mutex.RUnlock()
+	defer c.mutex.RLock()
+	c.mutex.Lock()
+	defer c.mutex.Unlock()
+	if c.SessionTicketKey == [32]byte{} {
+		if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+			panic(fmt.Sprintf("tls: unable to generate random session ticket key: %v", err))
+		}
+		// Write the deprecated prefix at the beginning so we know we created
+		// it. This key with the DEPRECATED prefix isn't used as an actual
+		// session ticket key, and is only randomized in case the application
+		// reuses it for some reason.
+		copy(c.SessionTicketKey[:], deprecatedSessionTicketKey)
+	} else if !bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) && len(c.sessionTicketKeys) == 0 {
+		c.sessionTicketKeys = []ticketKey{c.ticketKeyFromBytes(c.SessionTicketKey)}
+	}
+}
+
+// ticketKeys returns the ticketKeys for this connection.
+// If configForClient has explicitly set keys, those will
+// be returned. Otherwise, the keys on c will be used and
+// may be rotated if auto-managed.
+// During rotation, any expired session ticket keys are deleted from
+// c.sessionTicketKeys. If the session ticket key that is currently
+// encrypting tickets (ie. the first ticketKey in c.sessionTicketKeys)
+// is not fresh, then a new session ticket key will be
+// created and prepended to c.sessionTicketKeys.
+func (c *Config) ticketKeys(configForClient *Config) []ticketKey {
+	// If the ConfigForClient callback returned a Config with explicitly set
+	// keys, use those, otherwise just use the original Config.
+	if configForClient != nil {
+		configForClient.mutex.RLock()
+		if configForClient.SessionTicketsDisabled {
+			return nil
+		}
+		configForClient.initLegacySessionTicketKeyRLocked()
+		if len(configForClient.sessionTicketKeys) != 0 {
+			ret := configForClient.sessionTicketKeys
+			configForClient.mutex.RUnlock()
+			return ret
+		}
+		configForClient.mutex.RUnlock()
+	}
+
+	c.mutex.RLock()
+	defer c.mutex.RUnlock()
+	if c.SessionTicketsDisabled {
+		return nil
+	}
+	c.initLegacySessionTicketKeyRLocked()
+	if len(c.sessionTicketKeys) != 0 {
+		return c.sessionTicketKeys
+	}
+	// Fast path for the common case where the key is fresh enough.
+	if len(c.autoSessionTicketKeys) > 0 && c.time().Sub(c.autoSessionTicketKeys[0].created) < ticketKeyRotation {
+		return c.autoSessionTicketKeys
+	}
+
+	// autoSessionTicketKeys are managed by auto-rotation.
+	c.mutex.RUnlock()
+	defer c.mutex.RLock()
+	c.mutex.Lock()
+	defer c.mutex.Unlock()
+	// Re-check the condition in case it changed since obtaining the new lock.
+	if len(c.autoSessionTicketKeys) == 0 || c.time().Sub(c.autoSessionTicketKeys[0].created) >= ticketKeyRotation {
+		var newKey [32]byte
+		if _, err := io.ReadFull(c.rand(), newKey[:]); err != nil {
+			panic(fmt.Sprintf("unable to generate random session ticket key: %v", err))
+		}
+		valid := make([]ticketKey, 0, len(c.autoSessionTicketKeys)+1)
+		valid = append(valid, c.ticketKeyFromBytes(newKey))
+		for _, k := range c.autoSessionTicketKeys {
+			// While rotating the current key, also remove any expired ones.
+			if c.time().Sub(k.created) < ticketKeyLifetime {
+				valid = append(valid, k)
+			}
+		}
+		c.autoSessionTicketKeys = valid
+	}
+	return c.autoSessionTicketKeys
+}
+
+// SetSessionTicketKeys updates the session ticket keys for a server.
+//
+// The first key will be used when creating new tickets, while all keys can be
+// used for decrypting tickets. It is safe to call this function while the
+// server is running in order to rotate the session ticket keys. The function
+// will panic if keys is empty.
+//
+// Calling this function will turn off automatic session ticket key rotation.
+//
+// If multiple servers are terminating connections for the same host they should
+// all have the same session ticket keys. If the session ticket keys leaks,
+// previously recorded and future TLS connections using those keys might be
+// compromised.
+func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
+	if len(keys) == 0 {
+		panic("tls: keys must have at least one key")
+	}
+
+	newKeys := make([]ticketKey, len(keys))
+	for i, bytes := range keys {
+		newKeys[i] = c.ticketKeyFromBytes(bytes)
+	}
+
+	c.mutex.Lock()
+	c.sessionTicketKeys = newKeys
+	c.mutex.Unlock()
+}
+
+func (c *Config) rand() io.Reader {
+	r := c.Rand
+	if r == nil {
+		return rand.Reader
+	}
+	return r
+}
+
+func (c *Config) time() time.Time {
+	t := c.Time
+	if t == nil {
+		t = time.Now
+	}
+	return t()
+}
+
+func (c *Config) cipherSuites() []uint16 {
+	if c.CipherSuites != nil {
+		return c.CipherSuites
+	}
+	return defaultCipherSuites
+}
+
+var supportedVersions = []uint16{
+	VersionTLS13,
+	VersionTLS12,
+	VersionTLS11,
+	VersionTLS10,
+}
+
+// debugEnableTLS10 enables TLS 1.0. See issue 45428.
+var debugEnableTLS10 = false
+
+// roleClient and roleServer are meant to call supportedVersions and parents
+// with more readability at the callsite.
+const roleClient = true
+const roleServer = false
+
+func (c *Config) supportedVersions(isClient bool) []uint16 {
+	versions := make([]uint16, 0, len(supportedVersions))
+	for _, v := range supportedVersions {
+		if (c == nil || c.MinVersion == 0) && !debugEnableTLS10 &&
+			isClient && v < VersionTLS12 {
+			continue
+		}
+		if c != nil && c.MinVersion != 0 && v < c.MinVersion {
+			continue
+		}
+		if c != nil && c.MaxVersion != 0 && v > c.MaxVersion {
+			continue
+		}
+		versions = append(versions, v)
+	}
+	return versions
+}
+
+func (c *Config) supportedVersionsFromMin(isClient bool, minVersion uint16) []uint16 {
+	versions := make([]uint16, 0, len(supportedVersions))
+	for _, v := range supportedVersions {
+		if (c == nil || c.MinVersion == 0) && !debugEnableTLS10 &&
+			isClient && v < VersionTLS12 {
+			continue
+		}
+		if c != nil && c.MinVersion != 0 && v < c.MinVersion {
+			continue
+		}
+		if c != nil && c.MaxVersion != 0 && v > c.MaxVersion {
+			continue
+		}
+		if v < minVersion {
+			continue
+		}
+		versions = append(versions, v)
+	}
+	return versions
+}
+
+func (c *Config) maxSupportedVersion(isClient bool) uint16 {
+	supportedVersions := c.supportedVersions(isClient)
+	if len(supportedVersions) == 0 {
+		return 0
+	}
+	return supportedVersions[0]
+}
+
+// supportedVersionsFromMax returns a list of supported versions derived from a
+// legacy maximum version value. Note that only versions supported by this
+// library are returned. Any newer peer will use supportedVersions anyway.
+func supportedVersionsFromMax(maxVersion uint16) []uint16 {
+	versions := make([]uint16, 0, len(supportedVersions))
+	for _, v := range supportedVersions {
+		if v > maxVersion {
+			continue
+		}
+		versions = append(versions, v)
+	}
+	return versions
+}
+
+var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
+
+func (c *Config) curvePreferences() []CurveID {
+	if c == nil || len(c.CurvePreferences) == 0 {
+		return defaultCurvePreferences
+	}
+	return c.CurvePreferences
+}
+
+func (c *Config) supportsCurve(curve CurveID) bool {
+	for _, cc := range c.curvePreferences() {
+		if cc == curve {
+			return true
+		}
+	}
+	return false
+}
+
+// mutualVersion returns the protocol version to use given the advertised
+// versions of the peer. Priority is given to the peer preference order.
+func (c *Config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bool) {
+	supportedVersions := c.supportedVersions(isClient)
+	for _, peerVersion := range peerVersions {
+		for _, v := range supportedVersions {
+			if v == peerVersion {
+				return v, true
+			}
+		}
+	}
+	return 0, false
+}
+
+var errNoCertificates = errors.New("tls: no certificates configured")
+
+// getCertificate returns the best certificate for the given ClientHelloInfo,
+// defaulting to the first element of c.Certificates.
+func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) {
+	if c.GetCertificate != nil &&
+		(len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) {
+		cert, err := c.GetCertificate(clientHello)
+		if cert != nil || err != nil {
+			return cert, err
+		}
+	}
+
+	if len(c.Certificates) == 0 {
+		return nil, errNoCertificates
+	}
+
+	if len(c.Certificates) == 1 {
+		// There's only one choice, so no point doing any work.
+		return &c.Certificates[0], nil
+	}
+
+	if c.NameToCertificate != nil {
+		name := strings.ToLower(clientHello.ServerName)
+		if cert, ok := c.NameToCertificate[name]; ok {
+			return cert, nil
+		}
+		if len(name) > 0 {
+			labels := strings.Split(name, ".")
+			labels[0] = "*"
+			wildcardName := strings.Join(labels, ".")
+			if cert, ok := c.NameToCertificate[wildcardName]; ok {
+				return cert, nil
+			}
+		}
+	}
+
+	for _, cert := range c.Certificates {
+		if err := clientHello.SupportsCertificate(&cert); err == nil {
+			return &cert, nil
+		}
+	}
+
+	// If nothing matches, return the first certificate.
+	return &c.Certificates[0], nil
+}
+
+// SupportsCertificate returns nil if the provided certificate is supported by
+// the client that sent the ClientHello. Otherwise, it returns an error
+// describing the reason for the incompatibility.
+//
+// If this ClientHelloInfo was passed to a GetConfigForClient or GetCertificate
+// callback, this method will take into account the associated Config. Note that
+// if GetConfigForClient returns a different Config, the change can't be
+// accounted for by this method.
+//
+// This function will call x509.ParseCertificate unless c.Leaf is set, which can
+// incur a significant performance cost.
+func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
+	// Note we don't currently support certificate_authorities nor
+	// signature_algorithms_cert, and don't check the algorithms of the
+	// signatures on the chain (which anyway are a SHOULD, see RFC 8446,
+	// Section 4.4.2.2).
+
+	config := chi.config
+	if config == nil {
+		config = &Config{}
+	}
+	vers, ok := config.mutualVersion(roleServer, chi.SupportedVersions)
+	if !ok {
+		return errors.New("no mutually supported protocol versions")
+	}
+
+	// If the client specified the name they are trying to connect to, the
+	// certificate needs to be valid for it.
+	if chi.ServerName != "" {
+		x509Cert, err := c.leaf()
+		if err != nil {
+			return fmt.Errorf("failed to parse certificate: %w", err)
+		}
+		if err := x509Cert.VerifyHostname(chi.ServerName); err != nil {
+			return fmt.Errorf("certificate is not valid for requested server name: %w", err)
+		}
+	}
+
+	// supportsRSAFallback returns nil if the certificate and connection support
+	// the static RSA key exchange, and unsupported otherwise. The logic for
+	// supporting static RSA is completely disjoint from the logic for
+	// supporting signed key exchanges, so we just check it as a fallback.
+	supportsRSAFallback := func(unsupported error) error {
+		// TLS 1.3 dropped support for the static RSA key exchange.
+		if vers == VersionTLS13 {
+			return unsupported
+		}
+		// The static RSA key exchange works by decrypting a challenge with the
+		// RSA private key, not by signing, so check the PrivateKey implements
+		// crypto.Decrypter, like *rsa.PrivateKey does.
+		if priv, ok := c.PrivateKey.(crypto.Decrypter); ok {
+			if _, ok := priv.Public().(*rsa.PublicKey); !ok {
+				return unsupported
+			}
+		} else {
+			return unsupported
+		}
+		// Finally, there needs to be a mutual cipher suite that uses the static
+		// RSA key exchange instead of ECDHE.
+		rsaCipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
+			if c.flags&suiteECDHE != 0 {
+				return false
+			}
+			if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
+				return false
+			}
+			return true
+		})
+		if rsaCipherSuite == nil {
+			return unsupported
+		}
+		return nil
+	}
+
+	// If the client sent the signature_algorithms extension, ensure it supports
+	// schemes we can use with this certificate and TLS version.
+	if len(chi.SignatureSchemes) > 0 {
+		if _, err := selectSignatureScheme(vers, c, chi.SignatureSchemes); err != nil {
+			return supportsRSAFallback(err)
+		}
+	}
+
+	// In TLS 1.3 we are done because supported_groups is only relevant to the
+	// ECDHE computation, point format negotiation is removed, cipher suites are
+	// only relevant to the AEAD choice, and static RSA does not exist.
+	if vers == VersionTLS13 {
+		return nil
+	}
+
+	// The only signed key exchange we support is ECDHE.
+	if !supportsECDHE(config, chi.SupportedCurves, chi.SupportedPoints) {
+		return supportsRSAFallback(errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange"))
+	}
+
+	var ecdsaCipherSuite bool
+	if priv, ok := c.PrivateKey.(crypto.Signer); ok {
+		switch pub := priv.Public().(type) {
+		case *ecdsa.PublicKey:
+			var curve CurveID
+			switch pub.Curve {
+			case elliptic.P256():
+				curve = CurveP256
+			case elliptic.P384():
+				curve = CurveP384
+			case elliptic.P521():
+				curve = CurveP521
+			default:
+				return supportsRSAFallback(unsupportedCertificateError(c))
+			}
+			var curveOk bool
+			for _, c := range chi.SupportedCurves {
+				if c == curve && config.supportsCurve(c) {
+					curveOk = true
+					break
+				}
+			}
+			if !curveOk {
+				return errors.New("client doesn't support certificate curve")
+			}
+			ecdsaCipherSuite = true
+		case ed25519.PublicKey:
+			if vers < VersionTLS12 || len(chi.SignatureSchemes) == 0 {
+				return errors.New("connection doesn't support Ed25519")
+			}
+			ecdsaCipherSuite = true
+		case *rsa.PublicKey:
+		default:
+			return supportsRSAFallback(unsupportedCertificateError(c))
+		}
+	} else {
+		return supportsRSAFallback(unsupportedCertificateError(c))
+	}
+
+	// Make sure that there is a mutually supported cipher suite that works with
+	// this certificate. Cipher suite selection will then apply the logic in
+	// reverse to pick it. See also serverHandshakeState.cipherSuiteOk.
+	cipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
+		if c.flags&suiteECDHE == 0 {
+			return false
+		}
+		if c.flags&suiteECSign != 0 {
+			if !ecdsaCipherSuite {
+				return false
+			}
+		} else {
+			if ecdsaCipherSuite {
+				return false
+			}
+		}
+		if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
+			return false
+		}
+		return true
+	})
+	if cipherSuite == nil {
+		return supportsRSAFallback(errors.New("client doesn't support any cipher suites compatible with the certificate"))
+	}
+
+	return nil
+}
+
+// SupportsCertificate returns nil if the provided certificate is supported by
+// the server that sent the CertificateRequest. Otherwise, it returns an error
+// describing the reason for the incompatibility.
+func (cri *CertificateRequestInfo) SupportsCertificate(c *Certificate) error {
+	if _, err := selectSignatureScheme(cri.Version, c, cri.SignatureSchemes); err != nil {
+		return err
+	}
+
+	if len(cri.AcceptableCAs) == 0 {
+		return nil
+	}
+
+	for j, cert := range c.Certificate {
+		x509Cert := c.Leaf
+		// Parse the certificate if this isn't the leaf node, or if
+		// chain.Leaf was nil.
+		if j != 0 || x509Cert == nil {
+			var err error
+			if x509Cert, err = x509.ParseCertificate(cert); err != nil {
+				return fmt.Errorf("failed to parse certificate #%d in the chain: %w", j, err)
+			}
+		}
+
+		for _, ca := range cri.AcceptableCAs {
+			if bytes.Equal(x509Cert.RawIssuer, ca) {
+				return nil
+			}
+		}
+	}
+	return errors.New("chain is not signed by an acceptable CA")
+}
+
+// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
+// from the CommonName and SubjectAlternateName fields of each of the leaf
+// certificates.
+//
+// Deprecated: NameToCertificate only allows associating a single certificate
+// with a given name. Leave that field nil to let the library select the first
+// compatible chain from Certificates.
+func (c *Config) BuildNameToCertificate() {
+	c.NameToCertificate = make(map[string]*Certificate)
+	for i := range c.Certificates {
+		cert := &c.Certificates[i]
+		x509Cert, err := cert.leaf()
+		if err != nil {
+			continue
+		}
+		// If SANs are *not* present, some clients will consider the certificate
+		// valid for the name in the Common Name.
+		if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 {
+			c.NameToCertificate[x509Cert.Subject.CommonName] = cert
+		}
+		for _, san := range x509Cert.DNSNames {
+			c.NameToCertificate[san] = cert
+		}
+	}
+}
+
+const (
+	keyLogLabelTLS12           = "CLIENT_RANDOM"
+	keyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
+	keyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET"
+	keyLogLabelClientTraffic   = "CLIENT_TRAFFIC_SECRET_0"
+	keyLogLabelServerTraffic   = "SERVER_TRAFFIC_SECRET_0"
+)
+
+func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
+	if c.KeyLogWriter == nil {
+		return nil
+	}
+
+	logLine := []byte(fmt.Sprintf("%s %x %x\n", label, clientRandom, secret))
+
+	writerMutex.Lock()
+	_, err := c.KeyLogWriter.Write(logLine)
+	writerMutex.Unlock()
+
+	return err
+}
+
+// writerMutex protects all KeyLogWriters globally. It is rarely enabled,
+// and is only for debugging, so a global mutex saves space.
+var writerMutex sync.Mutex
+
+// A DelegatedCredentialPair contains a Delegated Credential and its
+// associated private key.
+type DelegatedCredentialPair struct {
+	// DC is the delegated credential.
+	DC *DelegatedCredential
+	// PrivateKey is the private key used to derive the public key of
+	// contained in DC. PrivateKey must implement crypto.Signer.
+	PrivateKey crypto.PrivateKey
+}
+
+// A Certificate is a chain of one or more certificates, leaf first.
+type Certificate struct {
+	Certificate [][]byte
+	// PrivateKey contains the private key corresponding to the public key in
+	// Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey.
+	// For a server up to TLS 1.2, it can also implement crypto.Decrypter with
+	// an RSA PublicKey.
+	PrivateKey crypto.PrivateKey
+	// SupportedSignatureAlgorithms is an optional list restricting what
+	// signature algorithms the PrivateKey can be used for.
+	SupportedSignatureAlgorithms []SignatureScheme
+	// OCSPStaple contains an optional OCSP response which will be served
+	// to clients that request it.
+	OCSPStaple []byte
+	// SignedCertificateTimestamps contains an optional list of Signed
+	// Certificate Timestamps which will be served to clients that request it.
+	SignedCertificateTimestamps [][]byte
+	// DelegatedCredentials are a list of Delegated Credentials with their
+	// corresponding private keys, signed by the leaf certificate.
+	// If there are no delegated credentials, this field is nil.
+	DelegatedCredentials []DelegatedCredentialPair
+	// DelegatedCredential is the delegated credential to be used in the
+	// handshake.
+	// If there are no delegated credentials, this field is nil.
+	// NOTE: Do not fill this field, as it will be filled depending on
+	// the provided list of delegated credentials.
+	DelegatedCredential []byte
+	// Leaf is the parsed form of the leaf certificate, which may be initialized
+	// using x509.ParseCertificate to reduce per-handshake processing. If nil,
+	// the leaf certificate will be parsed as needed.
+	Leaf *x509.Certificate
+}
+
+// leaf returns the parsed leaf certificate, either from c.Leaf or by parsing
+// the corresponding c.Certificate[0].
+func (c *Certificate) leaf() (*x509.Certificate, error) {
+	if c.Leaf != nil {
+		return c.Leaf, nil
+	}
+	return x509.ParseCertificate(c.Certificate[0])
+}
+
+type handshakeMessage interface {
+	marshal() []byte
+	unmarshal([]byte) bool
+}
+
+// lruSessionCache is a ClientSessionCache implementation that uses an LRU
+// caching strategy.
+type lruSessionCache struct {
+	sync.Mutex
+
+	m        map[string]*list.Element
+	q        *list.List
+	capacity int
+}
+
+type lruSessionCacheEntry struct {
+	sessionKey string
+	state      *ClientSessionState
+}
+
+// NewLRUClientSessionCache returns a ClientSessionCache with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUClientSessionCache(capacity int) ClientSessionCache {
+	const defaultSessionCacheCapacity = 64
+
+	if capacity < 1 {
+		capacity = defaultSessionCacheCapacity
+	}
+	return &lruSessionCache{
+		m:        make(map[string]*list.Element),
+		q:        list.New(),
+		capacity: capacity,
+	}
+}
+
+// Put adds the provided (sessionKey, cs) pair to the cache. If cs is nil, the entry
+// corresponding to sessionKey is removed from the cache instead.
+func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
+	c.Lock()
+	defer c.Unlock()
+
+	if elem, ok := c.m[sessionKey]; ok {
+		if cs == nil {
+			c.q.Remove(elem)
+			delete(c.m, sessionKey)
+		} else {
+			entry := elem.Value.(*lruSessionCacheEntry)
+			entry.state = cs
+			c.q.MoveToFront(elem)
+		}
+		return
+	}
+
+	if c.q.Len() < c.capacity {
+		entry := &lruSessionCacheEntry{sessionKey, cs}
+		c.m[sessionKey] = c.q.PushFront(entry)
+		return
+	}
+
+	elem := c.q.Back()
+	entry := elem.Value.(*lruSessionCacheEntry)
+	delete(c.m, entry.sessionKey)
+	entry.sessionKey = sessionKey
+	entry.state = cs
+	c.q.MoveToFront(elem)
+	c.m[sessionKey] = elem
+}
+
+// Get returns the ClientSessionState value associated with a given key. It
+// returns (nil, false) if no value is found.
+func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
+	c.Lock()
+	defer c.Unlock()
+
+	if elem, ok := c.m[sessionKey]; ok {
+		c.q.MoveToFront(elem)
+		return elem.Value.(*lruSessionCacheEntry).state, true
+	}
+	return nil, false
+}
+
+var emptyConfig Config
+
+func defaultConfig() *Config {
+	return &emptyConfig
+}
+
+func unexpectedMessageError(wanted, got any) error {
+	return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
+}
+
+func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool {
+	for _, s := range supportedSignatureAlgorithms {
+		if s == sigAlg {
+			return true
+		}
+	}
+	return false
+}

+ 116 - 0
transport/cloudflaretls/common_string.go

@@ -0,0 +1,116 @@
+// Code generated by "stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go"; DO NOT EDIT.
+
+package tls
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[PKCS1WithSHA256-1025]
+	_ = x[PKCS1WithSHA384-1281]
+	_ = x[PKCS1WithSHA512-1537]
+	_ = x[PSSWithSHA256-2052]
+	_ = x[PSSWithSHA384-2053]
+	_ = x[PSSWithSHA512-2054]
+	_ = x[ECDSAWithP256AndSHA256-1027]
+	_ = x[ECDSAWithP384AndSHA384-1283]
+	_ = x[ECDSAWithP521AndSHA512-1539]
+	_ = x[Ed25519-2055]
+	_ = x[PKCS1WithSHA1-513]
+	_ = x[ECDSAWithSHA1-515]
+}
+
+const (
+	_SignatureScheme_name_0 = "PKCS1WithSHA1"
+	_SignatureScheme_name_1 = "ECDSAWithSHA1"
+	_SignatureScheme_name_2 = "PKCS1WithSHA256"
+	_SignatureScheme_name_3 = "ECDSAWithP256AndSHA256"
+	_SignatureScheme_name_4 = "PKCS1WithSHA384"
+	_SignatureScheme_name_5 = "ECDSAWithP384AndSHA384"
+	_SignatureScheme_name_6 = "PKCS1WithSHA512"
+	_SignatureScheme_name_7 = "ECDSAWithP521AndSHA512"
+	_SignatureScheme_name_8 = "PSSWithSHA256PSSWithSHA384PSSWithSHA512Ed25519"
+)
+
+var (
+	_SignatureScheme_index_8 = [...]uint8{0, 13, 26, 39, 46}
+)
+
+func (i SignatureScheme) String() string {
+	switch {
+	case i == 513:
+		return _SignatureScheme_name_0
+	case i == 515:
+		return _SignatureScheme_name_1
+	case i == 1025:
+		return _SignatureScheme_name_2
+	case i == 1027:
+		return _SignatureScheme_name_3
+	case i == 1281:
+		return _SignatureScheme_name_4
+	case i == 1283:
+		return _SignatureScheme_name_5
+	case i == 1537:
+		return _SignatureScheme_name_6
+	case i == 1539:
+		return _SignatureScheme_name_7
+	case 2052 <= i && i <= 2055:
+		i -= 2052
+		return _SignatureScheme_name_8[_SignatureScheme_index_8[i]:_SignatureScheme_index_8[i+1]]
+	default:
+		return "SignatureScheme(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[CurveP256-23]
+	_ = x[CurveP384-24]
+	_ = x[CurveP521-25]
+	_ = x[X25519-29]
+}
+
+const (
+	_CurveID_name_0 = "CurveP256CurveP384CurveP521"
+	_CurveID_name_1 = "X25519"
+)
+
+var (
+	_CurveID_index_0 = [...]uint8{0, 9, 18, 27}
+)
+
+func (i CurveID) String() string {
+	switch {
+	case 23 <= i && i <= 25:
+		i -= 23
+		return _CurveID_name_0[_CurveID_index_0[i]:_CurveID_index_0[i+1]]
+	case i == 29:
+		return _CurveID_name_1
+	default:
+		return "CurveID(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+}
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[NoClientCert-0]
+	_ = x[RequestClientCert-1]
+	_ = x[RequireAnyClientCert-2]
+	_ = x[VerifyClientCertIfGiven-3]
+	_ = x[RequireAndVerifyClientCert-4]
+}
+
+const _ClientAuthType_name = "NoClientCertRequestClientCertRequireAnyClientCertVerifyClientCertIfGivenRequireAndVerifyClientCert"
+
+var _ClientAuthType_index = [...]uint8{0, 12, 29, 49, 72, 98}
+
+func (i ClientAuthType) String() string {
+	if i < 0 || i >= ClientAuthType(len(_ClientAuthType_index)-1) {
+		return "ClientAuthType(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _ClientAuthType_name[_ClientAuthType_index[i]:_ClientAuthType_index[i+1]]
+}

+ 1603 - 0
transport/cloudflaretls/conn.go

@@ -0,0 +1,1603 @@
+// 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.
+
+// TLS low level connection and record layer
+
+package tls
+
+import (
+	"bytes"
+	"context"
+	"crypto/cipher"
+	"crypto/subtle"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"hash"
+	"io"
+	"net"
+	"sync"
+	"sync/atomic"
+	"time"
+
+	"github.com/cloudflare/circl/hpke"
+)
+
+// A Conn represents a secured connection.
+// It implements the net.Conn interface.
+type Conn struct {
+	// constant
+	conn        net.Conn
+	isClient    bool
+	handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake
+
+	// handshakeStatus is 1 if the connection is currently transferring
+	// application data (i.e. is not currently processing a handshake).
+	// handshakeStatus == 1 implies handshakeErr == nil.
+	// This field is only to be accessed with sync/atomic.
+	handshakeStatus uint32
+	// constant after handshake; protected by handshakeMutex
+	handshakeMutex sync.Mutex
+	handshakeErr   error   // error resulting from handshake
+	vers           uint16  // TLS version
+	haveVers       bool    // version has been negotiated
+	config         *Config // configuration passed to constructor
+	// handshakes counts the number of handshakes performed on the
+	// connection so far. If renegotiation is disabled then this is either
+	// zero or one.
+	handshakes       int
+	didResume        bool // whether this connection was a session resumption
+	cipherSuite      uint16
+	ocspResponse     []byte   // stapled OCSP response
+	scts             [][]byte // signed certificate timestamps from server
+	peerCertificates []*x509.Certificate
+	// verifiedChains contains the certificate chains that we built, as
+	// opposed to the ones presented by the server.
+	verifiedChains [][]*x509.Certificate
+	// verifiedDC contains the Delegated Credential sent by the peer (if advertised
+	// and correctly processed), which has been verified against the leaf certificate.
+	verifiedDC *DelegatedCredential
+	// serverName contains the server name indicated by the client, if any.
+	serverName string
+	// secureRenegotiation is true if the server echoed the secure
+	// renegotiation extension. (This is meaningless as a server because
+	// renegotiation is not supported in that case.)
+	secureRenegotiation bool
+	// ekm is a closure for exporting keying material.
+	ekm func(label string, context []byte, length int) ([]byte, error)
+	// resumptionSecret is the resumption_master_secret for handling
+	// NewSessionTicket messages. nil if config.SessionTicketsDisabled.
+	resumptionSecret []byte
+
+	// ticketKeys is the set of active session ticket keys for this
+	// connection. The first one is used to encrypt new tickets and
+	// all are tried to decrypt tickets.
+	ticketKeys []ticketKey
+
+	// clientFinishedIsFirst is true if the client sent the first Finished
+	// message during the most recent handshake. This is recorded because
+	// the first transmitted Finished message is the tls-unique
+	// channel-binding value.
+	clientFinishedIsFirst bool
+
+	// closeNotifyErr is any error from sending the alertCloseNotify record.
+	closeNotifyErr error
+	// closeNotifySent is true if the Conn attempted to send an
+	// alertCloseNotify record.
+	closeNotifySent bool
+
+	// clientFinished and serverFinished contain the Finished message sent
+	// by the client or server in the most recent handshake. This is
+	// retained to support the renegotiation extension and tls-unique
+	// channel-binding.
+	clientFinished [12]byte
+	serverFinished [12]byte
+
+	// clientProtocol is the negotiated ALPN protocol.
+	clientProtocol string
+
+	// input/output
+	in, out   halfConn
+	rawInput  bytes.Buffer // raw input, starting with a record header
+	input     bytes.Reader // application data waiting to be read, from rawInput.Next
+	hand      bytes.Buffer // handshake data waiting to be read
+	buffering bool         // whether records are buffered in sendBuf
+	sendBuf   []byte       // a buffer of records waiting to be sent
+
+	// bytesSent counts the bytes of application data sent.
+	// packetsSent counts packets.
+	bytesSent   int64
+	packetsSent int64
+
+	// retryCount counts the number of consecutive non-advancing records
+	// received by Conn.readRecord. That is, records that neither advance the
+	// handshake, nor deliver application data. Protected by in.Mutex.
+	retryCount int
+
+	// activeCall is an atomic int32; the low bit is whether Close has
+	// been called. the rest of the bits are the number of goroutines
+	// in Conn.Write.
+	activeCall int32
+
+	tmp [16]byte
+
+	// State used for the ECH extension.
+	ech struct {
+		sealer hpke.Sealer // The client's HPKE context
+		opener hpke.Opener // The server's HPKE context
+
+		// The state shared by the client and server.
+		offered      bool   // Client offered ECH
+		greased      bool   // Client greased ECH
+		accepted     bool   // Server accepted ECH
+		retryConfigs []byte // The retry configurations
+		configId     uint8  // The ECH config id
+		maxNameLen   int    // maximum_name_len indicated by the ECH config
+	}
+}
+
+// Access to net.Conn methods.
+// Cannot just embed net.Conn because that would
+// export the struct field too.
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+	return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+	return c.conn.RemoteAddr()
+}
+
+// SetDeadline sets the read and write deadlines associated with the connection.
+// A zero value for t means Read and Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetDeadline(t time.Time) error {
+	return c.conn.SetDeadline(t)
+}
+
+// SetReadDeadline sets the read deadline on the underlying connection.
+// A zero value for t means Read will not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+	return c.conn.SetReadDeadline(t)
+}
+
+// SetWriteDeadline sets the write deadline on the underlying connection.
+// A zero value for t means Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+	return c.conn.SetWriteDeadline(t)
+}
+
+// NetConn returns the underlying connection that is wrapped by c.
+// Note that writing to or reading from this connection directly will corrupt the
+// TLS session.
+func (c *Conn) NetConn() net.Conn {
+	return c.conn
+}
+
+// A halfConn represents one direction of the record layer
+// connection, either sending or receiving.
+type halfConn struct {
+	sync.Mutex
+
+	err     error  // first permanent error
+	version uint16 // protocol version
+	cipher  any    // cipher algorithm
+	mac     hash.Hash
+	seq     [8]byte // 64-bit sequence number
+
+	scratchBuf [13]byte // to avoid allocs; interface method args escape
+
+	nextCipher any       // next encryption state
+	nextMac    hash.Hash // next MAC algorithm
+
+	trafficSecret []byte // current TLS 1.3 traffic secret
+}
+
+type permanentError struct {
+	err net.Error
+}
+
+func (e *permanentError) Error() string   { return e.err.Error() }
+func (e *permanentError) Unwrap() error   { return e.err }
+func (e *permanentError) Timeout() bool   { return e.err.Timeout() }
+func (e *permanentError) Temporary() bool { return false }
+
+func (hc *halfConn) setErrorLocked(err error) error {
+	if e, ok := err.(net.Error); ok {
+		hc.err = &permanentError{err: e}
+	} else {
+		hc.err = err
+	}
+	return hc.err
+}
+
+// prepareCipherSpec sets the encryption and MAC states
+// that a subsequent changeCipherSpec will use.
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher any, mac hash.Hash) {
+	hc.version = version
+	hc.nextCipher = cipher
+	hc.nextMac = mac
+}
+
+// changeCipherSpec changes the encryption and MAC states
+// to the ones previously passed to prepareCipherSpec.
+func (hc *halfConn) changeCipherSpec() error {
+	if hc.nextCipher == nil || hc.version == VersionTLS13 {
+		return alertInternalError
+	}
+	hc.cipher = hc.nextCipher
+	hc.mac = hc.nextMac
+	hc.nextCipher = nil
+	hc.nextMac = nil
+	for i := range hc.seq {
+		hc.seq[i] = 0
+	}
+	return nil
+}
+
+func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, secret []byte) {
+	hc.trafficSecret = secret
+	key, iv := suite.trafficKey(secret)
+	hc.cipher = suite.aead(key, iv)
+	for i := range hc.seq {
+		hc.seq[i] = 0
+	}
+}
+
+// incSeq increments the sequence number.
+func (hc *halfConn) incSeq() {
+	for i := 7; i >= 0; i-- {
+		hc.seq[i]++
+		if hc.seq[i] != 0 {
+			return
+		}
+	}
+
+	// Not allowed to let sequence number wrap.
+	// Instead, must renegotiate before it does.
+	// Not likely enough to bother.
+	panic("TLS: sequence number wraparound")
+}
+
+// explicitNonceLen returns the number of bytes of explicit nonce or IV included
+// in each record. Explicit nonces are present only in CBC modes after TLS 1.0
+// and in certain AEAD modes in TLS 1.2.
+func (hc *halfConn) explicitNonceLen() int {
+	if hc.cipher == nil {
+		return 0
+	}
+
+	switch c := hc.cipher.(type) {
+	case cipher.Stream:
+		return 0
+	case aead:
+		return c.explicitNonceLen()
+	case cbcMode:
+		// TLS 1.1 introduced a per-record explicit IV to fix the BEAST attack.
+		if hc.version >= VersionTLS11 {
+			return c.BlockSize()
+		}
+		return 0
+	default:
+		panic("unknown cipher type")
+	}
+}
+
+// extractPadding returns, in constant time, the length of the padding to remove
+// from the end of payload. It also returns a byte which is equal to 255 if the
+// padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2.
+func extractPadding(payload []byte) (toRemove int, good byte) {
+	if len(payload) < 1 {
+		return 0, 0
+	}
+
+	paddingLen := payload[len(payload)-1]
+	t := uint(len(payload)-1) - uint(paddingLen)
+	// if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+	good = byte(int32(^t) >> 31)
+
+	// The maximum possible padding length plus the actual length field
+	toCheck := 256
+	// The length of the padded data is public, so we can use an if here
+	if toCheck > len(payload) {
+		toCheck = len(payload)
+	}
+
+	for i := 0; i < toCheck; i++ {
+		t := uint(paddingLen) - uint(i)
+		// if i <= paddingLen then the MSB of t is zero
+		mask := byte(int32(^t) >> 31)
+		b := payload[len(payload)-1-i]
+		good &^= mask&paddingLen ^ mask&b
+	}
+
+	// We AND together the bits of good and replicate the result across
+	// all the bits.
+	good &= good << 4
+	good &= good << 2
+	good &= good << 1
+	good = uint8(int8(good) >> 7)
+
+	// Zero the padding length on error. This ensures any unchecked bytes
+	// are included in the MAC. Otherwise, an attacker that could
+	// distinguish MAC failures from padding failures could mount an attack
+	// similar to POODLE in SSL 3.0: given a good ciphertext that uses a
+	// full block's worth of padding, replace the final block with another
+	// block. If the MAC check passed but the padding check failed, the
+	// last byte of that block decrypted to the block size.
+	//
+	// See also macAndPaddingGood logic below.
+	paddingLen &= good
+
+	toRemove = int(paddingLen) + 1
+	return
+}
+
+func roundUp(a, b int) int {
+	return a + (b-a%b)%b
+}
+
+// cbcMode is an interface for block ciphers using cipher block chaining.
+type cbcMode interface {
+	cipher.BlockMode
+	SetIV([]byte)
+}
+
+// decrypt authenticates and decrypts the record if protection is active at
+// this stage. The returned plaintext might overlap with the input.
+func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
+	var plaintext []byte
+	typ := recordType(record[0])
+	payload := record[recordHeaderLen:]
+
+	// In TLS 1.3, change_cipher_spec messages are to be ignored without being
+	// decrypted. See RFC 8446, Appendix D.4.
+	if hc.version == VersionTLS13 && typ == recordTypeChangeCipherSpec {
+		return payload, typ, nil
+	}
+
+	paddingGood := byte(255)
+	paddingLen := 0
+
+	explicitNonceLen := hc.explicitNonceLen()
+
+	if hc.cipher != nil {
+		switch c := hc.cipher.(type) {
+		case cipher.Stream:
+			c.XORKeyStream(payload, payload)
+		case aead:
+			if len(payload) < explicitNonceLen {
+				return nil, 0, alertBadRecordMAC
+			}
+			nonce := payload[:explicitNonceLen]
+			if len(nonce) == 0 {
+				nonce = hc.seq[:]
+			}
+			payload = payload[explicitNonceLen:]
+
+			var additionalData []byte
+			if hc.version == VersionTLS13 {
+				additionalData = record[:recordHeaderLen]
+			} else {
+				additionalData = append(hc.scratchBuf[:0], hc.seq[:]...)
+				additionalData = append(additionalData, record[:3]...)
+				n := len(payload) - c.Overhead()
+				additionalData = append(additionalData, byte(n>>8), byte(n))
+			}
+
+			var err error
+			plaintext, err = c.Open(payload[:0], nonce, payload, additionalData)
+			if err != nil {
+				return nil, 0, alertBadRecordMAC
+			}
+		case cbcMode:
+			blockSize := c.BlockSize()
+			minPayload := explicitNonceLen + roundUp(hc.mac.Size()+1, blockSize)
+			if len(payload)%blockSize != 0 || len(payload) < minPayload {
+				return nil, 0, alertBadRecordMAC
+			}
+
+			if explicitNonceLen > 0 {
+				c.SetIV(payload[:explicitNonceLen])
+				payload = payload[explicitNonceLen:]
+			}
+			c.CryptBlocks(payload, payload)
+
+			// In a limited attempt to protect against CBC padding oracles like
+			// Lucky13, the data past paddingLen (which is secret) is passed to
+			// the MAC function as extra data, to be fed into the HMAC after
+			// computing the digest. This makes the MAC roughly constant time as
+			// long as the digest computation is constant time and does not
+			// affect the subsequent write, modulo cache effects.
+			paddingLen, paddingGood = extractPadding(payload)
+		default:
+			panic("unknown cipher type")
+		}
+
+		if hc.version == VersionTLS13 {
+			if typ != recordTypeApplicationData {
+				return nil, 0, alertUnexpectedMessage
+			}
+			if len(plaintext) > maxPlaintext+1 {
+				return nil, 0, alertRecordOverflow
+			}
+			// Remove padding and find the ContentType scanning from the end.
+			for i := len(plaintext) - 1; i >= 0; i-- {
+				if plaintext[i] != 0 {
+					typ = recordType(plaintext[i])
+					plaintext = plaintext[:i]
+					break
+				}
+				if i == 0 {
+					return nil, 0, alertUnexpectedMessage
+				}
+			}
+		}
+	} else {
+		plaintext = payload
+	}
+
+	if hc.mac != nil {
+		macSize := hc.mac.Size()
+		if len(payload) < macSize {
+			return nil, 0, alertBadRecordMAC
+		}
+
+		n := len(payload) - macSize - paddingLen
+		n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 }
+		record[3] = byte(n >> 8)
+		record[4] = byte(n)
+		remoteMAC := payload[n : n+macSize]
+		localMAC := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload[:n], payload[n+macSize:])
+
+		// This is equivalent to checking the MACs and paddingGood
+		// separately, but in constant-time to prevent distinguishing
+		// padding failures from MAC failures. Depending on what value
+		// of paddingLen was returned on bad padding, distinguishing
+		// bad MAC from bad padding can lead to an attack.
+		//
+		// See also the logic at the end of extractPadding.
+		macAndPaddingGood := subtle.ConstantTimeCompare(localMAC, remoteMAC) & int(paddingGood)
+		if macAndPaddingGood != 1 {
+			return nil, 0, alertBadRecordMAC
+		}
+
+		plaintext = payload[:n]
+	}
+
+	hc.incSeq()
+	return plaintext, typ, nil
+}
+
+// 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.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+	if total := len(in) + n; cap(in) >= total {
+		head = in[:total]
+	} else {
+		head = make([]byte, total)
+		copy(head, in)
+	}
+	tail = head[len(in):]
+	return
+}
+
+// encrypt encrypts payload, adding the appropriate nonce and/or MAC, and
+// appends it to record, which must already contain the record header.
+func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, error) {
+	if hc.cipher == nil {
+		return append(record, payload...), nil
+	}
+
+	var explicitNonce []byte
+	if explicitNonceLen := hc.explicitNonceLen(); explicitNonceLen > 0 {
+		record, explicitNonce = sliceForAppend(record, explicitNonceLen)
+		if _, isCBC := hc.cipher.(cbcMode); !isCBC && explicitNonceLen < 16 {
+			// The AES-GCM construction in TLS has an explicit nonce so that the
+			// nonce can be random. However, the nonce is only 8 bytes which is
+			// too small for a secure, random nonce. Therefore we use the
+			// sequence number as the nonce. The 3DES-CBC construction also has
+			// an 8 bytes nonce but its nonces must be unpredictable (see RFC
+			// 5246, Appendix F.3), forcing us to use randomness. That's not
+			// 3DES' biggest problem anyway because the birthday bound on block
+			// collision is reached first due to its similarly small block size
+			// (see the Sweet32 attack).
+			copy(explicitNonce, hc.seq[:])
+		} else {
+			if _, err := io.ReadFull(rand, explicitNonce); err != nil {
+				return nil, err
+			}
+		}
+	}
+
+	var dst []byte
+	switch c := hc.cipher.(type) {
+	case cipher.Stream:
+		mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
+		record, dst = sliceForAppend(record, len(payload)+len(mac))
+		c.XORKeyStream(dst[:len(payload)], payload)
+		c.XORKeyStream(dst[len(payload):], mac)
+	case aead:
+		nonce := explicitNonce
+		if len(nonce) == 0 {
+			nonce = hc.seq[:]
+		}
+
+		if hc.version == VersionTLS13 {
+			record = append(record, payload...)
+
+			// Encrypt the actual ContentType and replace the plaintext one.
+			record = append(record, record[0])
+			record[0] = byte(recordTypeApplicationData)
+
+			n := len(payload) + 1 + c.Overhead()
+			record[3] = byte(n >> 8)
+			record[4] = byte(n)
+
+			record = c.Seal(record[:recordHeaderLen],
+				nonce, record[recordHeaderLen:], record[:recordHeaderLen])
+		} else {
+			additionalData := append(hc.scratchBuf[:0], hc.seq[:]...)
+			additionalData = append(additionalData, record[:recordHeaderLen]...)
+			record = c.Seal(record, nonce, payload, additionalData)
+		}
+	case cbcMode:
+		mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
+		blockSize := c.BlockSize()
+		plaintextLen := len(payload) + len(mac)
+		paddingLen := blockSize - plaintextLen%blockSize
+		record, dst = sliceForAppend(record, plaintextLen+paddingLen)
+		copy(dst, payload)
+		copy(dst[len(payload):], mac)
+		for i := plaintextLen; i < len(dst); i++ {
+			dst[i] = byte(paddingLen - 1)
+		}
+		if len(explicitNonce) > 0 {
+			c.SetIV(explicitNonce)
+		}
+		c.CryptBlocks(dst, dst)
+	default:
+		panic("unknown cipher type")
+	}
+
+	// Update length to include nonce, MAC and any block padding needed.
+	n := len(record) - recordHeaderLen
+	record[3] = byte(n >> 8)
+	record[4] = byte(n)
+	hc.incSeq()
+
+	return record, nil
+}
+
+// RecordHeaderError is returned when a TLS record header is invalid.
+type RecordHeaderError struct {
+	// Msg contains a human readable string that describes the error.
+	Msg string
+	// RecordHeader contains the five bytes of TLS record header that
+	// triggered the error.
+	RecordHeader [5]byte
+	// Conn provides the underlying net.Conn in the case that a client
+	// sent an initial handshake that didn't look like TLS.
+	// It is nil if there's already been a handshake or a TLS alert has
+	// been written to the connection.
+	Conn net.Conn
+}
+
+func (e RecordHeaderError) Error() string { return "tls: " + e.Msg }
+
+func (c *Conn) newRecordHeaderError(conn net.Conn, msg string) (err RecordHeaderError) {
+	err.Msg = msg
+	err.Conn = conn
+	copy(err.RecordHeader[:], c.rawInput.Bytes())
+	return err
+}
+
+func (c *Conn) readRecord() error {
+	return c.readRecordOrCCS(false)
+}
+
+func (c *Conn) readChangeCipherSpec() error {
+	return c.readRecordOrCCS(true)
+}
+
+// readRecordOrCCS reads one or more TLS records from the connection and
+// updates the record layer state. Some invariants:
+//   - c.in must be locked
+//   - c.input must be empty
+//
+// During the handshake one and only one of the following will happen:
+//   - c.hand grows
+//   - c.in.changeCipherSpec is called
+//   - an error is returned
+//
+// After the handshake one and only one of the following will happen:
+//   - c.hand grows
+//   - c.input is set
+//   - an error is returned
+func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
+	if c.in.err != nil {
+		return c.in.err
+	}
+	handshakeComplete := c.handshakeComplete()
+
+	// This function modifies c.rawInput, which owns the c.input memory.
+	if c.input.Len() != 0 {
+		return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with pending application data"))
+	}
+	c.input.Reset(nil)
+
+	// Read header, payload.
+	if err := c.readFromUntil(c.conn, recordHeaderLen); err != nil {
+		// RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify
+		// is an error, but popular web sites seem to do this, so we accept it
+		// if and only if at the record boundary.
+		if err == io.ErrUnexpectedEOF && c.rawInput.Len() == 0 {
+			err = io.EOF
+		}
+		if e, ok := err.(net.Error); !ok || !e.Temporary() {
+			c.in.setErrorLocked(err)
+		}
+		return err
+	}
+	hdr := c.rawInput.Bytes()[:recordHeaderLen]
+	typ := recordType(hdr[0])
+
+	// No valid TLS record has a type of 0x80, however SSLv2 handshakes
+	// start with a uint16 length where the MSB is set and the first record
+	// is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
+	// an SSLv2 client.
+	if !handshakeComplete && typ == 0x80 {
+		c.sendAlert(alertProtocolVersion)
+		return c.in.setErrorLocked(c.newRecordHeaderError(nil, "unsupported SSLv2 handshake received"))
+	}
+
+	vers := uint16(hdr[1])<<8 | uint16(hdr[2])
+	n := int(hdr[3])<<8 | int(hdr[4])
+	if c.haveVers && c.vers != VersionTLS13 && vers != c.vers {
+		c.sendAlert(alertProtocolVersion)
+		msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers)
+		return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg))
+	}
+	if !c.haveVers {
+		// First message, be extra suspicious: this might not be a TLS
+		// client. Bail out before reading a full 'body', if possible.
+		// The current max version is 3.3 so if the version is >= 16.0,
+		// it's probably not real.
+		if (typ != recordTypeAlert && typ != recordTypeHandshake) || vers >= 0x1000 {
+			return c.in.setErrorLocked(c.newRecordHeaderError(c.conn, "first record does not look like a TLS handshake"))
+		}
+	}
+	if c.vers == VersionTLS13 && n > maxCiphertextTLS13 || n > maxCiphertext {
+		c.sendAlert(alertRecordOverflow)
+		msg := fmt.Sprintf("oversized record received with length %d", n)
+		return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg))
+	}
+	if err := c.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
+		if e, ok := err.(net.Error); !ok || !e.Temporary() {
+			c.in.setErrorLocked(err)
+		}
+		return err
+	}
+
+	// Process message.
+	record := c.rawInput.Next(recordHeaderLen + n)
+	data, typ, err := c.in.decrypt(record)
+	if err != nil {
+		return c.in.setErrorLocked(c.sendAlert(err.(alert)))
+	}
+	if len(data) > maxPlaintext {
+		return c.in.setErrorLocked(c.sendAlert(alertRecordOverflow))
+	}
+
+	// Application Data messages are always protected.
+	if c.in.cipher == nil && typ == recordTypeApplicationData {
+		return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+	}
+
+	if typ != recordTypeAlert && typ != recordTypeChangeCipherSpec && len(data) > 0 {
+		// This is a state-advancing message: reset the retry count.
+		c.retryCount = 0
+	}
+
+	// Handshake messages MUST NOT be interleaved with other record types in TLS 1.3.
+	if c.vers == VersionTLS13 && typ != recordTypeHandshake && c.hand.Len() > 0 {
+		return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+	}
+
+	switch typ {
+	default:
+		return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+
+	case recordTypeAlert:
+		if len(data) != 2 {
+			return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		if alert(data[1]) == alertCloseNotify {
+			return c.in.setErrorLocked(io.EOF)
+		}
+		if c.vers == VersionTLS13 {
+			if !c.isClient && c.ech.greased && alert(data[1]) == alertECHRequired {
+				// This condition indicates that the client intended to offer
+				// ECH, but did not use a known ECH config.
+				c.ech.offered = true
+				c.ech.greased = false
+			}
+			return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
+		}
+		switch data[0] {
+		case alertLevelWarning:
+			// Drop the record on the floor and retry.
+			return c.retryReadRecord(expectChangeCipherSpec)
+		case alertLevelError:
+			return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
+		default:
+			return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+
+	case recordTypeChangeCipherSpec:
+		if len(data) != 1 || data[0] != 1 {
+			return c.in.setErrorLocked(c.sendAlert(alertDecodeError))
+		}
+		// Handshake messages are not allowed to fragment across the CCS.
+		if c.hand.Len() > 0 {
+			return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		// In TLS 1.3, change_cipher_spec records are ignored until the
+		// Finished. See RFC 8446, Appendix D.4. Note that according to Section
+		// 5, a server can send a ChangeCipherSpec before its ServerHello, when
+		// c.vers is still unset. That's not useful though and suspicious if the
+		// server then selects a lower protocol version, so don't allow that.
+		if c.vers == VersionTLS13 {
+			return c.retryReadRecord(expectChangeCipherSpec)
+		}
+		if !expectChangeCipherSpec {
+			return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		if err := c.in.changeCipherSpec(); err != nil {
+			return c.in.setErrorLocked(c.sendAlert(err.(alert)))
+		}
+
+	case recordTypeApplicationData:
+		if !handshakeComplete || expectChangeCipherSpec {
+			return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		// Some OpenSSL servers send empty records in order to randomize the
+		// CBC IV. Ignore a limited number of empty records.
+		if len(data) == 0 {
+			return c.retryReadRecord(expectChangeCipherSpec)
+		}
+		// Note that data is owned by c.rawInput, following the Next call above,
+		// to avoid copying the plaintext. This is safe because c.rawInput is
+		// not read from or written to until c.input is drained.
+		c.input.Reset(data)
+
+	case recordTypeHandshake:
+		if len(data) == 0 || expectChangeCipherSpec {
+			return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		c.hand.Write(data)
+	}
+
+	return nil
+}
+
+// retryReadRecord recurses into readRecordOrCCS to drop a non-advancing record, like
+// a warning alert, empty application_data, or a change_cipher_spec in TLS 1.3.
+func (c *Conn) retryReadRecord(expectChangeCipherSpec bool) error {
+	c.retryCount++
+	if c.retryCount > maxUselessRecords {
+		c.sendAlert(alertUnexpectedMessage)
+		return c.in.setErrorLocked(errors.New("tls: too many ignored records"))
+	}
+	return c.readRecordOrCCS(expectChangeCipherSpec)
+}
+
+// atLeastReader reads from R, stopping with EOF once at least N bytes have been
+// read. It is different from an io.LimitedReader in that it doesn't cut short
+// the last Read call, and in that it considers an early EOF an error.
+type atLeastReader struct {
+	R io.Reader
+	N int64
+}
+
+func (r *atLeastReader) Read(p []byte) (int, error) {
+	if r.N <= 0 {
+		return 0, io.EOF
+	}
+	n, err := r.R.Read(p)
+	r.N -= int64(n) // won't underflow unless len(p) >= n > 9223372036854775809
+	if r.N > 0 && err == io.EOF {
+		return n, io.ErrUnexpectedEOF
+	}
+	if r.N <= 0 && err == nil {
+		return n, io.EOF
+	}
+	return n, err
+}
+
+// readFromUntil reads from r into c.rawInput until c.rawInput contains
+// at least n bytes or else returns an error.
+func (c *Conn) readFromUntil(r io.Reader, n int) error {
+	if c.rawInput.Len() >= n {
+		return nil
+	}
+	needs := n - c.rawInput.Len()
+	// There might be extra input waiting on the wire. Make a best effort
+	// attempt to fetch it so that it can be used in (*Conn).Read to
+	// "predict" closeNotify alerts.
+	c.rawInput.Grow(needs + bytes.MinRead)
+	_, err := c.rawInput.ReadFrom(&atLeastReader{r, int64(needs)})
+	return err
+}
+
+// sendAlert sends a TLS alert message.
+func (c *Conn) sendAlertLocked(err alert) error {
+	switch err {
+	case alertNoRenegotiation, alertCloseNotify:
+		c.tmp[0] = alertLevelWarning
+	default:
+		c.tmp[0] = alertLevelError
+	}
+	c.tmp[1] = byte(err)
+
+	_, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2])
+	if err == alertCloseNotify {
+		// closeNotify is a special case in that it isn't an error.
+		return writeErr
+	}
+
+	return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+}
+
+// sendAlert sends a TLS alert message.
+func (c *Conn) sendAlert(err alert) error {
+	c.out.Lock()
+	defer c.out.Unlock()
+	return c.sendAlertLocked(err)
+}
+
+const (
+	// tcpMSSEstimate is a conservative estimate of the TCP maximum segment
+	// size (MSS). A constant is used, rather than querying the kernel for
+	// the actual MSS, to avoid complexity. The value here is the IPv6
+	// minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40
+	// bytes) and a TCP header with timestamps (32 bytes).
+	tcpMSSEstimate = 1208
+
+	// recordSizeBoostThreshold is the number of bytes of application data
+	// sent after which the TLS record size will be increased to the
+	// maximum.
+	recordSizeBoostThreshold = 128 * 1024
+)
+
+// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the
+// next application data record. There is the following trade-off:
+//
+//   - For latency-sensitive applications, such as web browsing, each TLS
+//     record should fit in one TCP segment.
+//   - For throughput-sensitive applications, such as large file transfers,
+//     larger TLS records better amortize framing and encryption overheads.
+//
+// A simple heuristic that works well in practice is to use small records for
+// the first 1MB of data, then use larger records for subsequent data, and
+// reset back to smaller records after the connection becomes idle. See "High
+// Performance Web Networking", Chapter 4, or:
+// https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/
+//
+// In the interests of simplicity and determinism, this code does not attempt
+// to reset the record size once the connection is idle, however.
+func (c *Conn) maxPayloadSizeForWrite(typ recordType) int {
+	if c.config.DynamicRecordSizingDisabled || typ != recordTypeApplicationData {
+		return maxPlaintext
+	}
+
+	if c.bytesSent >= recordSizeBoostThreshold {
+		return maxPlaintext
+	}
+
+	// Subtract TLS overheads to get the maximum payload size.
+	payloadBytes := tcpMSSEstimate - recordHeaderLen - c.out.explicitNonceLen()
+	if c.out.cipher != nil {
+		switch ciph := c.out.cipher.(type) {
+		case cipher.Stream:
+			payloadBytes -= c.out.mac.Size()
+		case cipher.AEAD:
+			payloadBytes -= ciph.Overhead()
+		case cbcMode:
+			blockSize := ciph.BlockSize()
+			// The payload must fit in a multiple of blockSize, with
+			// room for at least one padding byte.
+			payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1
+			// The MAC is appended before padding so affects the
+			// payload size directly.
+			payloadBytes -= c.out.mac.Size()
+		default:
+			panic("unknown cipher type")
+		}
+	}
+	if c.vers == VersionTLS13 {
+		payloadBytes-- // encrypted ContentType
+	}
+
+	// Allow packet growth in arithmetic progression up to max.
+	pkt := c.packetsSent
+	c.packetsSent++
+	if pkt > 1000 {
+		return maxPlaintext // avoid overflow in multiply below
+	}
+
+	n := payloadBytes * int(pkt+1)
+	if n > maxPlaintext {
+		n = maxPlaintext
+	}
+	return n
+}
+
+func (c *Conn) write(data []byte) (int, error) {
+	if c.buffering {
+		c.sendBuf = append(c.sendBuf, data...)
+		return len(data), nil
+	}
+
+	n, err := c.conn.Write(data)
+	c.bytesSent += int64(n)
+	return n, err
+}
+
+func (c *Conn) flush() (int, error) {
+	if len(c.sendBuf) == 0 {
+		return 0, nil
+	}
+
+	n, err := c.conn.Write(c.sendBuf)
+	c.bytesSent += int64(n)
+	c.sendBuf = nil
+	c.buffering = false
+	return n, err
+}
+
+// outBufPool pools the record-sized scratch buffers used by writeRecordLocked.
+var outBufPool = sync.Pool{
+	New: func() any {
+		return new([]byte)
+	},
+}
+
+// writeRecordLocked writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
+	outBufPtr := outBufPool.Get().(*[]byte)
+	outBuf := *outBufPtr
+	defer func() {
+		// You might be tempted to simplify this by just passing &outBuf to Put,
+		// but that would make the local copy of the outBuf slice header escape
+		// to the heap, causing an allocation. Instead, we keep around the
+		// pointer to the slice header returned by Get, which is already on the
+		// heap, and overwrite and return that.
+		*outBufPtr = outBuf
+		outBufPool.Put(outBufPtr)
+	}()
+
+	var n int
+	for len(data) > 0 {
+		m := len(data)
+		if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload {
+			m = maxPayload
+		}
+
+		_, outBuf = sliceForAppend(outBuf[:0], recordHeaderLen)
+		outBuf[0] = byte(typ)
+		vers := c.vers
+		if vers == 0 {
+			// Some TLS servers fail if the record version is
+			// greater than TLS 1.0 for the initial ClientHello.
+			vers = VersionTLS10
+		} else if vers == VersionTLS13 {
+			// TLS 1.3 froze the record layer version to 1.2.
+			// See RFC 8446, Section 5.1.
+			vers = VersionTLS12
+		}
+		outBuf[1] = byte(vers >> 8)
+		outBuf[2] = byte(vers)
+		outBuf[3] = byte(m >> 8)
+		outBuf[4] = byte(m)
+
+		var err error
+		outBuf, err = c.out.encrypt(outBuf, data[:m], c.config.rand())
+		if err != nil {
+			return n, err
+		}
+		if _, err := c.write(outBuf); err != nil {
+			return n, err
+		}
+		n += m
+		data = data[m:]
+	}
+
+	if typ == recordTypeChangeCipherSpec && c.vers != VersionTLS13 {
+		if err := c.out.changeCipherSpec(); err != nil {
+			return n, c.sendAlertLocked(err.(alert))
+		}
+	}
+
+	return n, nil
+}
+
+// writeRecord writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
+	c.out.Lock()
+	defer c.out.Unlock()
+
+	return c.writeRecordLocked(typ, data)
+}
+
+// readHandshake reads the next handshake message from
+// the record layer.
+func (c *Conn) readHandshake() (any, error) {
+	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)
+	var m handshakeMessage
+	switch data[0] {
+	case typeHelloRequest:
+		m = new(helloRequestMsg)
+	case typeClientHello:
+		m = new(clientHelloMsg)
+	case typeServerHello:
+		m = new(serverHelloMsg)
+	case typeNewSessionTicket:
+		if c.vers == VersionTLS13 {
+			m = new(newSessionTicketMsgTLS13)
+		} else {
+			m = new(newSessionTicketMsg)
+		}
+	case typeCertificate:
+		if c.vers == VersionTLS13 {
+			m = new(certificateMsgTLS13)
+		} else {
+			m = new(certificateMsg)
+		}
+	case typeCertificateRequest:
+		if c.vers == VersionTLS13 {
+			m = new(certificateRequestMsgTLS13)
+		} else {
+			m = &certificateRequestMsg{
+				hasSignatureAlgorithm: c.vers >= VersionTLS12,
+			}
+		}
+	case typeCertificateStatus:
+		m = new(certificateStatusMsg)
+	case typeServerKeyExchange:
+		m = new(serverKeyExchangeMsg)
+	case typeServerHelloDone:
+		m = new(serverHelloDoneMsg)
+	case typeClientKeyExchange:
+		m = new(clientKeyExchangeMsg)
+	case typeCertificateVerify:
+		m = &certificateVerifyMsg{
+			hasSignatureAlgorithm: c.vers >= VersionTLS12,
+		}
+	case typeFinished:
+		m = new(finishedMsg)
+	case typeEncryptedExtensions:
+		m = new(encryptedExtensionsMsg)
+	case typeEndOfEarlyData:
+		m = new(endOfEarlyDataMsg)
+	case typeKeyUpdate:
+		m = new(keyUpdateMsg)
+	default:
+		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+	}
+
+	// The handshake message unmarshalers
+	// expect to be able to keep references to data,
+	// so pass in a fresh copy that won't be overwritten.
+	data = append([]byte(nil), data...)
+
+	if !m.unmarshal(data) {
+		return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+	}
+	return m, nil
+}
+
+var errShutdown = errors.New("tls: protocol is shutdown")
+
+// Write writes data to the connection.
+//
+// As Write calls Handshake, in order to prevent indefinite blocking a deadline
+// must be set for both Read and Write before Write is called when the handshake
+// has not yet completed. See SetDeadline, SetReadDeadline, and
+// SetWriteDeadline.
+func (c *Conn) Write(b []byte) (int, error) {
+	// interlock with Close below
+	for {
+		x := atomic.LoadInt32(&c.activeCall)
+		if x&1 != 0 {
+			return 0, net.ErrClosed
+		}
+		if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
+			break
+		}
+	}
+	defer atomic.AddInt32(&c.activeCall, -2)
+
+	if err := c.Handshake(); err != nil {
+		return 0, err
+	}
+
+	c.out.Lock()
+	defer c.out.Unlock()
+
+	if err := c.out.err; err != nil {
+		return 0, err
+	}
+
+	if !c.handshakeComplete() {
+		return 0, alertInternalError
+	}
+
+	if c.closeNotifySent {
+		return 0, errShutdown
+	}
+
+	// TLS 1.0 is susceptible to a chosen-plaintext
+	// attack when using block mode ciphers due to predictable IVs.
+	// This can be prevented by splitting each Application Data
+	// record into two records, effectively randomizing the IV.
+	//
+	// https://www.openssl.org/~bodo/tls-cbc.txt
+	// https://bugzilla.mozilla.org/show_bug.cgi?id=665814
+	// https://www.imperialviolet.org/2012/01/15/beastfollowup.html
+
+	var m int
+	if len(b) > 1 && c.vers == VersionTLS10 {
+		if _, ok := c.out.cipher.(cipher.BlockMode); ok {
+			n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1])
+			if err != nil {
+				return n, c.out.setErrorLocked(err)
+			}
+			m, b = 1, b[1:]
+		}
+	}
+
+	n, err := c.writeRecordLocked(recordTypeApplicationData, b)
+	return n + m, c.out.setErrorLocked(err)
+}
+
+// handleRenegotiation processes a HelloRequest handshake message.
+func (c *Conn) handleRenegotiation() error {
+	if c.vers == VersionTLS13 {
+		return errors.New("tls: internal error: unexpected renegotiation")
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	helloReq, ok := msg.(*helloRequestMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(helloReq, msg)
+	}
+
+	if !c.isClient {
+		return c.sendAlert(alertNoRenegotiation)
+	}
+
+	switch c.config.Renegotiation {
+	case RenegotiateNever:
+		return c.sendAlert(alertNoRenegotiation)
+	case RenegotiateOnceAsClient:
+		if c.handshakes > 1 {
+			return c.sendAlert(alertNoRenegotiation)
+		}
+	case RenegotiateFreelyAsClient:
+		// Ok.
+	default:
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: unknown Renegotiation value")
+	}
+
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	atomic.StoreUint32(&c.handshakeStatus, 0)
+	if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil {
+		c.handshakes++
+	}
+	return c.handshakeErr
+}
+
+// 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 {
+	if c.vers != VersionTLS13 {
+		return c.handleRenegotiation()
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	c.retryCount++
+	if c.retryCount > maxUselessRecords {
+		c.sendAlert(alertUnexpectedMessage)
+		return c.in.setErrorLocked(errors.New("tls: too many non-advancing records"))
+	}
+
+	switch msg := msg.(type) {
+	case *newSessionTicketMsgTLS13:
+		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)
+	}
+}
+
+func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
+	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)
+
+	if keyUpdate.updateRequested {
+		c.out.Lock()
+		defer c.out.Unlock()
+
+		msg := &keyUpdateMsg{}
+		_, err := c.writeRecordLocked(recordTypeHandshake, msg.marshal())
+		if err != nil {
+			// Surface the error at the next write.
+			c.out.setErrorLocked(err)
+			return nil
+		}
+
+		newSecret := cipherSuite.nextTrafficSecret(c.out.trafficSecret)
+		c.out.setTrafficSecret(cipherSuite, newSecret)
+	}
+
+	return nil
+}
+
+// Read reads data from the connection.
+//
+// As Read calls Handshake, in order to prevent indefinite blocking a deadline
+// must be set for both Read and Write before Read is called when the handshake
+// has not yet completed. See SetDeadline, SetReadDeadline, and
+// SetWriteDeadline.
+func (c *Conn) Read(b []byte) (int, error) {
+	if err := c.Handshake(); err != nil {
+		return 0, err
+	}
+	if len(b) == 0 {
+		// Put this after Handshake, in case people were calling
+		// Read(nil) for the side effect of the Handshake.
+		return 0, nil
+	}
+
+	c.in.Lock()
+	defer c.in.Unlock()
+
+	for c.input.Len() == 0 {
+		if err := c.readRecord(); err != nil {
+			return 0, err
+		}
+		for c.hand.Len() > 0 {
+			if err := c.handlePostHandshakeMessage(); err != nil {
+				return 0, err
+			}
+		}
+	}
+
+	n, _ := c.input.Read(b)
+
+	// If a close-notify alert is waiting, read it so that we can return (n,
+	// EOF) instead of (n, nil), to signal to the HTTP response reading
+	// goroutine that the connection is now closed. This eliminates a race
+	// where the HTTP response reading goroutine would otherwise not observe
+	// the EOF until its next read, by which time a client goroutine might
+	// have already tried to reuse the HTTP connection for a new request.
+	// See https://golang.org/cl/76400046 and https://golang.org/issue/3514
+	if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 &&
+		recordType(c.rawInput.Bytes()[0]) == recordTypeAlert {
+		if err := c.readRecord(); err != nil {
+			return n, err // will be io.EOF on closeNotify
+		}
+	}
+
+	return n, nil
+}
+
+// Close closes the connection.
+func (c *Conn) Close() error {
+	// Interlock with Conn.Write above.
+	var x int32
+	for {
+		x = atomic.LoadInt32(&c.activeCall)
+		if x&1 != 0 {
+			return net.ErrClosed
+		}
+		if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) {
+			break
+		}
+	}
+	if x != 0 {
+		// io.Writer and io.Closer should not be used concurrently.
+		// If Close is called while a Write is currently in-flight,
+		// interpret that as a sign that this Close is really just
+		// being used to break the Write and/or clean up resources and
+		// avoid sending the alertCloseNotify, which may block
+		// waiting on handshakeMutex or the c.out mutex.
+		return c.conn.Close()
+	}
+
+	var alertErr error
+	if c.handshakeComplete() {
+		if err := c.closeNotify(); err != nil {
+			alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err)
+		}
+	}
+
+	if err := c.conn.Close(); err != nil {
+		return err
+	}
+
+	// Resolve ECH status.
+	if !c.isClient && c.config.MaxVersion < VersionTLS13 {
+		c.handleCFEvent(CFEventECHServerStatus(echStatusBypassed))
+	} else if !c.ech.offered {
+		if !c.ech.greased {
+			c.handleCFEvent(CFEventECHClientStatus(echStatusBypassed))
+		} else {
+			c.handleCFEvent(CFEventECHClientStatus(echStatusOuter))
+		}
+	} else {
+		c.handleCFEvent(CFEventECHClientStatus(echStatusInner))
+		if !c.ech.accepted {
+			if len(c.ech.retryConfigs) > 0 {
+				c.handleCFEvent(CFEventECHServerStatus(echStatusOuter))
+			} else {
+				c.handleCFEvent(CFEventECHServerStatus(echStatusBypassed))
+			}
+		} else {
+			c.handleCFEvent(CFEventECHServerStatus(echStatusInner))
+		}
+	}
+
+	return alertErr
+}
+
+var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete")
+
+// CloseWrite shuts down the writing side of the connection. It should only be
+// called once the handshake has completed and does not call CloseWrite on the
+// underlying connection. Most callers should just use Close.
+func (c *Conn) CloseWrite() error {
+	if !c.handshakeComplete() {
+		return errEarlyCloseWrite
+	}
+
+	return c.closeNotify()
+}
+
+func (c *Conn) closeNotify() error {
+	c.out.Lock()
+	defer c.out.Unlock()
+
+	if !c.closeNotifySent {
+		// Set a Write Deadline to prevent possibly blocking forever.
+		c.SetWriteDeadline(time.Now().Add(time.Second * 5))
+		c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
+		c.closeNotifySent = true
+		// Any subsequent writes will fail.
+		c.SetWriteDeadline(time.Now())
+	}
+	return c.closeNotifyErr
+}
+
+// Handshake runs the client or server handshake
+// protocol if it has not yet been run.
+//
+// Most uses of this package need not call Handshake explicitly: the
+// first Read or Write will call it automatically.
+//
+// For control over canceling or setting a timeout on a handshake, use
+// HandshakeContext or the Dialer's DialContext method instead.
+func (c *Conn) Handshake() error {
+	return c.HandshakeContext(context.Background())
+}
+
+// HandshakeContext runs the client or server handshake
+// protocol if it has not yet been run.
+//
+// The provided Context must be non-nil. If the context is canceled before
+// the handshake is complete, the handshake is interrupted and an error is returned.
+// Once the handshake has completed, cancellation of the context will not affect the
+// connection.
+//
+// Most uses of this package need not call HandshakeContext explicitly: the
+// first Read or Write will call it automatically.
+func (c *Conn) HandshakeContext(ctx context.Context) error {
+	// Delegate to unexported method for named return
+	// without confusing documented signature.
+	return c.handshakeContext(ctx)
+}
+
+func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
+	// Fast sync/atomic-based exit if there is no handshake in flight and the
+	// last one succeeded without an error. Avoids the expensive context setup
+	// and mutex for most Read and Write calls.
+	if c.handshakeComplete() {
+		return nil
+	}
+
+	handshakeCtx, cancel := context.WithCancel(ctx)
+	// Note: defer this before starting the "interrupter" goroutine
+	// so that we can tell the difference between the input being canceled and
+	// this cancellation. In the former case, we need to close the connection.
+	defer cancel()
+
+	// Start the "interrupter" goroutine, if this context might be canceled.
+	// (The background context cannot).
+	//
+	// The interrupter goroutine waits for the input context to be done and
+	// closes the connection if this happens before the function returns.
+	if ctx.Done() != nil {
+		done := make(chan struct{})
+		interruptRes := make(chan error, 1)
+		defer func() {
+			close(done)
+			if ctxErr := <-interruptRes; ctxErr != nil {
+				// Return context error to user.
+				ret = ctxErr
+			}
+		}()
+		go func() {
+			select {
+			case <-handshakeCtx.Done():
+				// Close the connection, discarding the error
+				_ = c.conn.Close()
+				interruptRes <- handshakeCtx.Err()
+			case <-done:
+				interruptRes <- nil
+			}
+		}()
+	}
+
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	if err := c.handshakeErr; err != nil {
+		return err
+	}
+	if c.handshakeComplete() {
+		return nil
+	}
+
+	c.in.Lock()
+	defer c.in.Unlock()
+
+	c.handshakeErr = c.handshakeFn(handshakeCtx)
+	if c.handshakeErr == nil {
+		c.handshakes++
+	} else {
+		// If an error occurred during the handshake try to flush the
+		// alert that might be left in the buffer.
+		c.flush()
+	}
+
+	if c.handshakeErr == nil && !c.handshakeComplete() {
+		c.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
+	}
+	if c.handshakeErr != nil && c.handshakeComplete() {
+		panic("tls: internal error: handshake returned an error but is marked successful")
+	}
+
+	return c.handshakeErr
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	return c.connectionStateLocked()
+}
+
+func (c *Conn) connectionStateLocked() ConnectionState {
+	var state ConnectionState
+	state.HandshakeComplete = c.handshakeComplete()
+	state.Version = c.vers
+	state.NegotiatedProtocol = c.clientProtocol
+	state.DidResume = c.didResume
+	state.NegotiatedProtocolIsMutual = true
+	state.ServerName = c.serverName
+	state.CipherSuite = c.cipherSuite
+	state.PeerCertificates = c.peerCertificates
+	state.VerifiedChains = c.verifiedChains
+	if c.verifiedDC != nil {
+		state.VerifiedDC = true
+	}
+	state.SignedCertificateTimestamps = c.scts
+	state.OCSPResponse = c.ocspResponse
+	state.ECHAccepted = c.ech.accepted
+	state.ECHOffered = c.ech.offered || c.ech.greased
+	state.CFControl = c.config.CFControl
+	if !c.didResume && c.vers != VersionTLS13 {
+		if c.clientFinishedIsFirst {
+			state.TLSUnique = c.clientFinished[:]
+		} else {
+			state.TLSUnique = c.serverFinished[:]
+		}
+	}
+	if c.config.Renegotiation != RenegotiateNever {
+		state.ekm = noExportedKeyingMaterial
+	} else {
+		state.ekm = c.ekm
+	}
+	return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	return c.ocspResponse
+}
+
+// VerifyHostname checks that the peer certificate chain is valid for
+// connecting to host. If so, it returns nil; if not, it returns an error
+// describing the problem.
+func (c *Conn) VerifyHostname(host string) error {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	if !c.isClient {
+		return errors.New("tls: VerifyHostname called on TLS server connection")
+	}
+	if !c.handshakeComplete() {
+		return errors.New("tls: handshake has not yet been performed")
+	}
+	if len(c.verifiedChains) == 0 {
+		return errors.New("tls: handshake did not verify certificate chain")
+	}
+	return c.peerCertificates[0].VerifyHostname(host)
+}
+
+func (c *Conn) handshakeComplete() bool {
+	return atomic.LoadUint32(&c.handshakeStatus) == 1
+}
+
+func (c *Conn) handleCFEvent(event CFEvent) {
+	if c.config.CFEventHandler != nil {
+		c.config.CFEventHandler(event)
+	}
+}

+ 550 - 0
transport/cloudflaretls/delegated_credentials.go

@@ -0,0 +1,550 @@
+// Copyright 2020-2021 Cloudflare, Inc. All rights reserved. Use of this source code
+// is governed by a BSD-style license that can be found in the LICENSE file.
+
+package tls
+
+// Delegated Credentials for TLS
+// (https://tools.ietf.org/html/draft-ietf-tls-subcerts) is an IETF Internet
+// draft and proposed TLS extension. If the client or server supports this
+// extension, then the server or client may use a "delegated credential" as the
+// signing key in the handshake. A delegated credential is a short lived
+// public/secret key pair delegated to the peer by an entity trusted by the
+// corresponding peer. This allows a reverse proxy to terminate a TLS connection
+// on behalf of the entity. Credentials can't be revoked; in order to
+// mitigate risk in case the reverse proxy is compromised, the credential is only
+// valid for a short time (days, hours, or even minutes).
+
+import (
+	"bytes"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"time"
+
+	"golang.org/x/crypto/cryptobyte"
+)
+
+const (
+	// In the absence of an application profile standard specifying otherwise,
+	// the maximum validity period is set to 7 days.
+	dcMaxTTLSeconds   = 60 * 60 * 24 * 7
+	dcMaxTTL          = time.Duration(dcMaxTTLSeconds * time.Second)
+	dcMaxPubLen       = (1 << 24) - 1 // Bytes
+	dcMaxSignatureLen = (1 << 16) - 1 // Bytes
+)
+
+const (
+	undefinedSignatureScheme SignatureScheme = 0x0000
+)
+
+var extensionDelegatedCredential = []int{1, 3, 6, 1, 4, 1, 44363, 44}
+
+// isValidForDelegation returns true if a certificate can be used for Delegated
+// Credentials.
+func isValidForDelegation(cert *x509.Certificate) bool {
+	// Check that the digitalSignature key usage is set.
+	// The certificate must contains the digitalSignature KeyUsage.
+	if (cert.KeyUsage & x509.KeyUsageDigitalSignature) == 0 {
+		return false
+	}
+
+	// Check that the certificate has the DelegationUsage extension and that
+	// it's marked as non-critical (See Section 4.2 of RFC5280).
+	for _, extension := range cert.Extensions {
+		if extension.Id.Equal(extensionDelegatedCredential) {
+			if extension.Critical {
+				return false
+			}
+			return true
+		}
+	}
+	return false
+}
+
+// isExpired returns true if the credential has expired. The end of the validity
+// interval is defined as the delegator certificate's notBefore field ('start')
+// plus dc.cred.validTime seconds. This function simply checks that the current time
+// ('now') is before the end of the validity interval.
+func (dc *DelegatedCredential) isExpired(start, now time.Time) bool {
+	end := start.Add(dc.cred.validTime)
+	return !now.Before(end)
+}
+
+// invalidTTL returns true if the credential's validity period is longer than the
+// maximum permitted. This is defined by the certificate's notBefore field
+// ('start') plus the dc.validTime, minus the current time ('now').
+func (dc *DelegatedCredential) invalidTTL(start, now time.Time) bool {
+	return dc.cred.validTime > (now.Sub(start) + dcMaxTTL).Round(time.Second)
+}
+
+// credential stores the public components of a Delegated Credential.
+type credential struct {
+	// The amount of time for which the credential is valid. Specifically, the
+	// the credential expires 'validTime' seconds after the 'notBefore' of the
+	// delegation certificate. The delegator shall not issue Delegated
+	// Credentials that are valid for more than 7 days from the current time.
+	//
+	// When this data structure is serialized, this value is converted to a
+	// uint32 representing the duration in seconds.
+	validTime time.Duration
+	// The signature scheme associated with the credential public key.
+	// This is expected to be the same as the CertificateVerify.algorithm
+	// sent by the client or server.
+	expCertVerfAlgo SignatureScheme
+	// The credential's public key.
+	publicKey crypto.PublicKey
+}
+
+// DelegatedCredential stores a Delegated Credential with the credential and its
+// signature.
+type DelegatedCredential struct {
+	// The serialized form of the Delegated Credential.
+	raw []byte
+
+	// Cred stores the public components of a Delegated Credential.
+	cred *credential
+
+	// The signature scheme used to sign the Delegated Credential.
+	algorithm SignatureScheme
+
+	// The Credential's delegation: a signature that binds the credential to
+	// the end-entity certificate's public key.
+	signature []byte
+}
+
+// marshalPublicKeyInfo returns a DER encoded PublicKeyInfo
+// from a Delegated Credential (as defined in the X.509 standard).
+// The following key types are currently supported: *ecdsa.PublicKey
+// and ed25519.PublicKey. Unsupported key types result in an error.
+// rsa.PublicKey is not supported as defined by the draft.
+func (cred *credential) marshalPublicKeyInfo() ([]byte, error) {
+	switch cred.expCertVerfAlgo {
+	case ECDSAWithP256AndSHA256,
+		ECDSAWithP384AndSHA384,
+		ECDSAWithP521AndSHA512,
+		Ed25519:
+		rawPub, err := x509.MarshalPKIXPublicKey(cred.publicKey)
+		if err != nil {
+			return nil, err
+		}
+
+		return rawPub, nil
+
+	default:
+		return nil, fmt.Errorf("tls: unsupported signature scheme: 0x%04x", cred.expCertVerfAlgo)
+	}
+}
+
+// marshal encodes the credential struct of the Delegated Credential.
+func (cred *credential) marshal() ([]byte, error) {
+	var b cryptobyte.Builder
+
+	b.AddUint32(uint32(cred.validTime / time.Second))
+	b.AddUint16(uint16(cred.expCertVerfAlgo))
+
+	// Encode the public key
+	rawPub, err := cred.marshalPublicKeyInfo()
+	if err != nil {
+		return nil, err
+	}
+	// Assert that the public key encoding is no longer than 2^24-1 bytes.
+	if len(rawPub) > dcMaxPubLen {
+		return nil, errors.New("tls: public key length exceeds 2^24-1 limit")
+	}
+
+	b.AddUint24(uint32(len(rawPub)))
+	b.AddBytes(rawPub)
+
+	raw := b.BytesOrPanic()
+	return raw, nil
+}
+
+// unmarshalCredential decodes serialized bytes and returns a credential, if possible.
+func unmarshalCredential(raw []byte) (*credential, error) {
+	if len(raw) < 10 {
+		return nil, errors.New("tls: Delegated Credential is not valid: invalid length")
+	}
+
+	s := cryptobyte.String(raw)
+	var t uint32
+	if !s.ReadUint32(&t) {
+		return nil, errors.New("tls: Delegated Credential is not valid")
+	}
+	validTime := time.Duration(t) * time.Second
+
+	var pubAlgo uint16
+	if !s.ReadUint16(&pubAlgo) {
+		return nil, errors.New("tls: Delegated Credential is not valid")
+	}
+	algo := SignatureScheme(pubAlgo)
+
+	var pubLen uint32
+	s.ReadUint24(&pubLen)
+
+	pubKey, err := x509.ParsePKIXPublicKey(s)
+	if err != nil {
+		return nil, err
+	}
+
+	return &credential{validTime, algo, pubKey}, nil
+}
+
+// getCredentialLen returns the number of bytes comprising the serialized
+// credential struct inside the Delegated Credential.
+func getCredentialLen(raw []byte) (int, error) {
+	if len(raw) < 10 {
+		return 0, errors.New("tls: Delegated Credential is not valid")
+	}
+
+	var read []byte
+	s := cryptobyte.String(raw)
+	s.ReadBytes(&read, 6)
+
+	var pubLen uint32
+	s.ReadUint24(&pubLen)
+	if !(pubLen > 0) {
+		return 0, errors.New("tls: Delegated Credential is not valid")
+	}
+
+	raw = raw[6:]
+	if len(raw) < int(pubLen) {
+		return 0, errors.New("tls: Delegated Credential is not valid")
+	}
+
+	return 9 + int(pubLen), nil
+}
+
+// getHash maps the SignatureScheme to its corresponding hash function.
+func getHash(scheme SignatureScheme) crypto.Hash {
+	switch scheme {
+	case ECDSAWithP256AndSHA256:
+		return crypto.SHA256
+	case ECDSAWithP384AndSHA384:
+		return crypto.SHA384
+	case ECDSAWithP521AndSHA512:
+		return crypto.SHA512
+	case Ed25519:
+		return directSigning
+	case PKCS1WithSHA256, PSSWithSHA256:
+		return crypto.SHA256
+	case PSSWithSHA384:
+		return crypto.SHA384
+	case PSSWithSHA512:
+		return crypto.SHA512
+	default:
+		return 0 // Unknown hash function
+	}
+}
+
+// getECDSACurve maps the SignatureScheme to its corresponding ecdsa elliptic.Curve.
+func getECDSACurve(scheme SignatureScheme) elliptic.Curve {
+	switch scheme {
+	case ECDSAWithP256AndSHA256:
+		return elliptic.P256()
+	case ECDSAWithP384AndSHA384:
+		return elliptic.P384()
+	case ECDSAWithP521AndSHA512:
+		return elliptic.P521()
+	default:
+		return nil
+	}
+}
+
+// prepareDelegationSignatureInput returns the message that the delegator is going to sign.
+func prepareDelegationSignatureInput(hash crypto.Hash, cred *credential, dCert []byte, algo SignatureScheme, isClient bool) ([]byte, error) {
+	header := make([]byte, 64)
+	for i := range header {
+		header[i] = 0x20
+	}
+
+	var context string
+	if !isClient {
+		context = "TLS, server delegated credentials\x00"
+	} else {
+		context = "TLS, client delegated credentials\x00"
+	}
+
+	rawCred, err := cred.marshal()
+	if err != nil {
+		return nil, err
+	}
+
+	var rawAlgo [2]byte
+	binary.BigEndian.PutUint16(rawAlgo[:], uint16(algo))
+
+	if hash == directSigning {
+		b := &bytes.Buffer{}
+		b.Write(header)
+		io.WriteString(b, context)
+		b.Write(dCert)
+		b.Write(rawCred)
+		b.Write(rawAlgo[:])
+		return b.Bytes(), nil
+	}
+
+	h := hash.New()
+	h.Write(header)
+	io.WriteString(h, context)
+	h.Write(dCert)
+	h.Write(rawCred)
+	h.Write(rawAlgo[:])
+	return h.Sum(nil), nil
+}
+
+// Extract the algorithm used to sign the Delegated Credential from the
+// end-entity (leaf) certificate.
+func getSignatureAlgorithm(cert *Certificate) (SignatureScheme, error) {
+	switch sk := cert.PrivateKey.(type) {
+	case *ecdsa.PrivateKey:
+		pk := sk.Public().(*ecdsa.PublicKey)
+		curveName := pk.Curve.Params().Name
+		certAlg := cert.Leaf.PublicKeyAlgorithm
+		if certAlg == x509.ECDSA && curveName == "P-256" {
+			return ECDSAWithP256AndSHA256, nil
+		} else if certAlg == x509.ECDSA && curveName == "P-384" {
+			return ECDSAWithP384AndSHA384, nil
+		} else if certAlg == x509.ECDSA && curveName == "P-521" {
+			return ECDSAWithP521AndSHA512, nil
+		} else {
+			return undefinedSignatureScheme, fmt.Errorf("using curve %s for %s is not supported", curveName, cert.Leaf.SignatureAlgorithm)
+		}
+	case ed25519.PrivateKey:
+		return Ed25519, nil
+	case *rsa.PrivateKey:
+		// If the certificate has the RSAEncryption OID there are a number of valid signature schemes that may sign the DC.
+		// In the absence of better information, we make a reasonable choice.
+		return PSSWithSHA256, nil
+	default:
+		return undefinedSignatureScheme, fmt.Errorf("tls: unsupported algorithm for signing Delegated Credential")
+	}
+}
+
+// NewDelegatedCredential creates a new Delegated Credential using 'cert' for
+// delegation, depending if the caller is the client or the server (defined by
+// 'isClient'). It generates a public/private key pair for the provided signature
+// algorithm ('pubAlgo') and it defines a validity interval (defined
+// by 'cert.Leaf.notBefore' and 'validTime'). It signs the Delegated Credential
+// using 'cert.PrivateKey'.
+func NewDelegatedCredential(cert *Certificate, pubAlgo SignatureScheme, validTime time.Duration, isClient bool) (*DelegatedCredential, crypto.PrivateKey, error) {
+	// The granularity of DC validity is seconds.
+	validTime = validTime.Round(time.Second)
+
+	// Parse the leaf certificate if needed.
+	var err error
+	if cert.Leaf == nil {
+		if len(cert.Certificate[0]) == 0 {
+			return nil, nil, errors.New("tls: missing leaf certificate for Delegated Credential")
+		}
+		cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
+		if err != nil {
+			return nil, nil, err
+		}
+	}
+
+	// Check that the leaf certificate can be used for delegation.
+	if !isValidForDelegation(cert.Leaf) {
+		return nil, nil, errors.New("tls: certificate not authorized for delegation")
+	}
+
+	sigAlgo, err := getSignatureAlgorithm(cert)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// Generate the Delegated Credential key pair based on the provided scheme
+	var privK crypto.PrivateKey
+	var pubK crypto.PublicKey
+	switch pubAlgo {
+	case ECDSAWithP256AndSHA256,
+		ECDSAWithP384AndSHA384,
+		ECDSAWithP521AndSHA512:
+		privK, err = ecdsa.GenerateKey(getECDSACurve(pubAlgo), rand.Reader)
+		if err != nil {
+			return nil, nil, err
+		}
+		pubK = privK.(*ecdsa.PrivateKey).Public()
+	case Ed25519:
+		pubK, privK, err = ed25519.GenerateKey(rand.Reader)
+		if err != nil {
+			return nil, nil, err
+		}
+	default:
+		return nil, nil, fmt.Errorf("tls: unsupported algorithm for Delegated Credential: %s", pubAlgo)
+	}
+
+	// Prepare the credential for signing
+	hash := getHash(sigAlgo)
+	credential := &credential{validTime, pubAlgo, pubK}
+	values, err := prepareDelegationSignatureInput(hash, credential, cert.Leaf.Raw, sigAlgo, isClient)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	var sig []byte
+	switch sk := cert.PrivateKey.(type) {
+	case *ecdsa.PrivateKey:
+		opts := crypto.SignerOpts(hash)
+		sig, err = sk.Sign(rand.Reader, values, opts)
+		if err != nil {
+			return nil, nil, err
+		}
+	case ed25519.PrivateKey:
+		opts := crypto.SignerOpts(hash)
+		sig, err = sk.Sign(rand.Reader, values, opts)
+		if err != nil {
+			return nil, nil, err
+		}
+	case *rsa.PrivateKey:
+		opts := &rsa.PSSOptions{
+			SaltLength: rsa.PSSSaltLengthEqualsHash,
+			Hash:       hash,
+		}
+		sig, err = rsa.SignPSS(rand.Reader, sk, hash, values, opts)
+		if err != nil {
+			return nil, nil, err
+		}
+	default:
+		return nil, nil, fmt.Errorf("tls: unsupported key type for Delegated Credential")
+	}
+
+	if len(sig) > dcMaxSignatureLen {
+		return nil, nil, errors.New("tls: unable to create a Delegated Credential")
+	}
+
+	return &DelegatedCredential{
+		cred:      credential,
+		algorithm: sigAlgo,
+		signature: sig,
+	}, privK, nil
+}
+
+// Validate validates the Delegated Credential by checking that the signature is
+// valid, that it hasn't expired, and that the TTL is valid. It also checks that
+// certificate can be used for delegation.
+func (dc *DelegatedCredential) Validate(cert *x509.Certificate, isClient bool, now time.Time, certVerifyMsg *certificateVerifyMsg) bool {
+	if dc.isExpired(cert.NotBefore, now) {
+		return false
+	}
+
+	if dc.invalidTTL(cert.NotBefore, now) {
+		return false
+	}
+
+	if dc.cred.expCertVerfAlgo != certVerifyMsg.signatureAlgorithm {
+		return false
+	}
+
+	if !isValidForDelegation(cert) {
+		return false
+	}
+
+	hash := getHash(dc.algorithm)
+	in, err := prepareDelegationSignatureInput(hash, dc.cred, cert.Raw, dc.algorithm, isClient)
+	if err != nil {
+		return false
+	}
+
+	switch dc.algorithm {
+	case ECDSAWithP256AndSHA256,
+		ECDSAWithP384AndSHA384,
+		ECDSAWithP521AndSHA512:
+		pk, ok := cert.PublicKey.(*ecdsa.PublicKey)
+		if !ok {
+			return false
+		}
+
+		return ecdsa.VerifyASN1(pk, in, dc.signature)
+	case Ed25519:
+		pk, ok := cert.PublicKey.(ed25519.PublicKey)
+		if !ok {
+			return false
+		}
+
+		return ed25519.Verify(pk, in, dc.signature)
+	case PSSWithSHA256,
+		PSSWithSHA384,
+		PSSWithSHA512:
+		pk, ok := cert.PublicKey.(*rsa.PublicKey)
+		if !ok {
+			return false
+		}
+		hash := getHash(dc.algorithm)
+		return rsa.VerifyPSS(pk, hash, in, dc.signature, nil) == nil
+	default:
+		return false
+	}
+}
+
+// Marshal encodes a DelegatedCredential structure. It also sets dc.Raw to that
+// encoding.
+func (dc *DelegatedCredential) Marshal() ([]byte, error) {
+	if len(dc.signature) > dcMaxSignatureLen {
+		return nil, errors.New("tls: delegated credential is not valid")
+	}
+	if len(dc.signature) == 0 {
+		return nil, errors.New("tls: delegated credential has no signature")
+	}
+
+	raw, err := dc.cred.marshal()
+	if err != nil {
+		return nil, err
+	}
+
+	var b cryptobyte.Builder
+	b.AddBytes(raw)
+	b.AddUint16(uint16(dc.algorithm))
+	b.AddUint16(uint16(len(dc.signature)))
+	b.AddBytes(dc.signature)
+
+	dc.raw = b.BytesOrPanic()
+	return dc.raw, nil
+}
+
+// UnmarshalDelegatedCredential decodes a DelegatedCredential structure.
+func UnmarshalDelegatedCredential(raw []byte) (*DelegatedCredential, error) {
+	rawCredentialLen, err := getCredentialLen(raw)
+	if err != nil {
+		return nil, err
+	}
+
+	credential, err := unmarshalCredential(raw[:rawCredentialLen])
+	if err != nil {
+		return nil, err
+	}
+
+	raw = raw[rawCredentialLen:]
+	if len(raw) < 4 {
+		return nil, errors.New("tls: Delegated Credential is not valid")
+	}
+
+	s := cryptobyte.String(raw)
+
+	var algo uint16
+	if !s.ReadUint16(&algo) {
+		return nil, errors.New("tls: Delegated Credential is not valid")
+	}
+
+	var rawSignatureLen uint16
+	if !s.ReadUint16(&rawSignatureLen) {
+		return nil, errors.New("tls: Delegated Credential is not valid")
+	}
+
+	var sig []byte
+	if !s.ReadBytes(&sig, int(rawSignatureLen)) {
+		return nil, errors.New("tls: Delegated Credential is not valid")
+	}
+
+	return &DelegatedCredential{
+		cred:      credential,
+		algorithm: SignatureScheme(algo),
+		signature: sig,
+	}, nil
+}

+ 1079 - 0
transport/cloudflaretls/ech.go

@@ -0,0 +1,1079 @@
+// Copyright 2020 Cloudflare, Inc. All rights reserved. Use of this source code
+// is governed by a BSD-style license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"errors"
+	"fmt"
+	"io"
+
+	"github.com/cloudflare/circl/hpke"
+	"golang.org/x/crypto/cryptobyte"
+)
+
+const (
+	// Constants for TLS operations
+	echAcceptConfLabel    = "ech accept confirmation"
+	echAcceptConfHRRLabel = "hrr ech accept confirmation"
+
+	// Constants for HPKE operations
+	echHpkeInfoSetup = "tls ech"
+
+	// When sent in the ClientHello, the first byte of the payload of the ECH
+	// extension indicates whether the message is the ClientHelloOuter or
+	// ClientHelloInner.
+	echClientHelloOuterVariant uint8 = 0
+	echClientHelloInnerVariant uint8 = 1
+)
+
+var zeros = [8]byte{}
+
+// echOfferOrGrease is called by the client after generating its ClientHello
+// message to decide if it will offer or GREASE ECH. It does neither if ECH is
+// disabled. Returns a pair of ClientHello messages, hello and helloInner. If
+// offering ECH, these are the ClienthelloOuter and ClientHelloInner
+// respectively. Otherwise, hello is the ClientHello and helloInner == nil.
+//
+// TODO(cjpatton): "[When offering ECH, the client] MUST NOT offer to resume any
+// session for TLS 1.2 and below [in ClientHelloInner]."
+func (c *Conn) echOfferOrGrease(helloBase *clientHelloMsg) (hello, helloInner *clientHelloMsg, err error) {
+	config := c.config
+
+	if !config.ECHEnabled || testingECHTriggerBypassBeforeHRR {
+		// Bypass ECH.
+		return helloBase, nil, nil
+	}
+
+	// Choose the ECHConfig to use for this connection. If none is available, or
+	// if we're not offering TLS 1.3 or above, then GREASE.
+	echConfig := config.echSelectConfig()
+	if echConfig == nil || config.maxSupportedVersion(roleClient) < VersionTLS13 {
+		var err error
+
+		// Generate a dummy ClientECH.
+		helloBase.ech, err = echGenerateGreaseExt(config.rand())
+		if err != nil {
+			return nil, nil, fmt.Errorf("tls: ech: failed to generate grease ECH: %s", err)
+		}
+
+		// GREASE ECH.
+		c.ech.offered = false
+		c.ech.greased = true
+		helloBase.raw = nil
+		return helloBase, nil, nil
+	}
+
+	// Store the ECH config parameters that are needed later.
+	c.ech.configId = echConfig.configId
+	c.ech.maxNameLen = int(echConfig.maxNameLen)
+
+	// Generate the HPKE context. Store it in case of HRR.
+	var enc []byte
+	enc, c.ech.sealer, err = echConfig.setupSealer(config.rand())
+	if err != nil {
+		return nil, nil, fmt.Errorf("tls: ech: %s", err)
+	}
+
+	// ClientHelloInner is constructed from the base ClientHello. The payload of
+	// the "encrypted_client_hello" extension is a single 1 byte indicating that
+	// this is the ClientHelloInner.
+	helloInner = helloBase
+	helloInner.ech = []byte{echClientHelloInnerVariant}
+
+	// Ensure that only TLS 1.3 and above are offered in the inner handshake.
+	if v := helloInner.supportedVersions; len(v) == 0 || v[len(v)-1] < VersionTLS13 {
+		return nil, nil, errors.New("tls: ech: only TLS 1.3 is allowed in ClientHelloInner")
+	}
+
+	// ClientHelloOuter is constructed by generating a fresh ClientHello and
+	// copying "session_id" from ClientHelloInner, setting "server_name" to the
+	// client-facing server, and adding the "encrypted_client_hello" extension.
+	//
+	// In addition, we discard the "key_share" and instead use the one from
+	// ClientHelloInner.
+	hello, _, err = c.makeClientHello(config.MinVersion)
+	if err != nil {
+		return nil, nil, fmt.Errorf("tls: ech: %s", err)
+	}
+	hello.sessionId = helloBase.sessionId
+	hello.serverName = hostnameInSNI(string(echConfig.rawPublicName))
+	if err := c.echUpdateClientHelloOuter(hello, helloInner, enc); err != nil {
+		return nil, nil, err
+	}
+
+	// Offer ECH.
+	c.ech.offered = true
+	helloInner.raw = nil
+	hello.raw = nil
+	return hello, helloInner, nil
+}
+
+// echUpdateClientHelloOuter is called by the client to construct the payload of
+// the ECH extension in the outer handshake.
+func (c *Conn) echUpdateClientHelloOuter(hello, helloInner *clientHelloMsg, enc []byte) error {
+	var (
+		ech echClientOuter
+		err error
+	)
+
+	// Copy all compressed extensions from ClientHelloInner into
+	// ClientHelloOuter.
+	for _, ext := range echOuterExtensions() {
+		echCopyExtensionFromClientHelloInner(hello, helloInner, ext)
+	}
+
+	// Always copy the "key_shares" extension from ClientHelloInner, regardless
+	// of whether it gets compressed.
+	hello.keyShares = helloInner.keyShares
+
+	_, kdf, aead := c.ech.sealer.Suite().Params()
+	ech.handle.suite.kdfId = uint16(kdf)
+	ech.handle.suite.aeadId = uint16(aead)
+	ech.handle.configId = c.ech.configId
+	ech.handle.enc = enc
+
+	// EncodedClientHelloInner
+	helloInner.raw = nil
+	encodedHelloInner := echEncodeClientHelloInner(
+		helloInner.marshal(),
+		len(helloInner.serverName),
+		c.ech.maxNameLen)
+	if encodedHelloInner == nil {
+		return errors.New("tls: ech: encoding of EncodedClientHelloInner failed")
+	}
+
+	// ClientHelloOuterAAD
+	hello.raw = nil
+	hello.ech = ech.marshal()
+	helloOuterAad := echEncodeClientHelloOuterAAD(hello.marshal(),
+		aead.CipherLen(uint(len(encodedHelloInner))))
+	if helloOuterAad == nil {
+		return errors.New("tls: ech: encoding of ClientHelloOuterAAD failed")
+	}
+
+	ech.payload, err = c.ech.sealer.Seal(encodedHelloInner, helloOuterAad)
+	if err != nil {
+		return fmt.Errorf("tls: ech: seal failed: %s", err)
+	}
+	if testingECHTriggerPayloadDecryptError {
+		ech.payload[0] ^= 0xff // Inauthentic ciphertext
+	}
+	ech.raw = nil
+	hello.ech = ech.marshal()
+
+	helloInner.raw = nil
+	hello.raw = nil
+	return nil
+}
+
+// echAcceptOrReject is called by the client-facing server to determine whether
+// ECH was offered by the client, and if so, whether to accept or reject. The
+// return value is the ClientHello that will be used for the connection.
+//
+// This function is called prior to processing the ClientHello. In case of
+// HelloRetryRequest, it is also called before processing the second
+// ClientHello. This is indicated by the afterHRR flag.
+func (c *Conn) echAcceptOrReject(hello *clientHelloMsg, afterHRR bool) (*clientHelloMsg, error) {
+	config := c.config
+	p := config.ServerECHProvider
+
+	if !config.echCanAccept() {
+		// Bypass ECH.
+		return hello, nil
+	}
+
+	if len(hello.ech) > 0 { // The ECH extension is present
+		switch hello.ech[0] {
+		case echClientHelloInnerVariant: // inner handshake
+			if len(hello.ech) > 1 {
+				c.sendAlert(alertIllegalParameter)
+				return nil, errors.New("ech: inner handshake has non-empty payload")
+			}
+
+			// Continue as the backend server.
+			return hello, nil
+		case echClientHelloOuterVariant: // outer handshake
+		default:
+			c.sendAlert(alertIllegalParameter)
+			return nil, errors.New("ech: inner handshake has non-empty payload")
+		}
+	} else {
+		if c.ech.offered {
+			// This occurs if the server accepted prior to HRR, but the client
+			// failed to send the ECH extension in the second ClientHelloOuter. This
+			// would cause ClientHelloOuter to be used after ClientHelloInner, which
+			// is illegal.
+			c.sendAlert(alertMissingExtension)
+			return nil, errors.New("ech: hrr: bypass after offer")
+		}
+
+		// Bypass ECH.
+		return hello, nil
+	}
+
+	if afterHRR && !c.ech.offered && !c.ech.greased {
+		// The client bypassed ECH prior to HRR, but not after. This could
+		// cause ClientHelloInner to be used after ClientHelloOuter, which is
+		// illegal.
+		c.sendAlert(alertIllegalParameter)
+		return nil, errors.New("ech: hrr: offer or grease after bypass")
+	}
+
+	// Parse ClientECH.
+	ech, err := echUnmarshalClientOuter(hello.ech)
+	if err != nil {
+		c.sendAlert(alertIllegalParameter)
+		return nil, fmt.Errorf("ech: failed to parse extension: %s", err)
+	}
+
+	// Make sure that the HPKE suite and config id don't change across HRR and
+	// that the encapsulated key is not present after HRR.
+	if afterHRR && c.ech.offered {
+		_, kdf, aead := c.ech.opener.Suite().Params()
+		if ech.handle.suite.kdfId != uint16(kdf) ||
+			ech.handle.suite.aeadId != uint16(aead) ||
+			ech.handle.configId != c.ech.configId ||
+			len(ech.handle.enc) > 0 {
+			c.sendAlert(alertIllegalParameter)
+			return nil, errors.New("ech: hrr: illegal handle in second hello")
+		}
+	}
+
+	// Store the config id in case of HRR.
+	c.ech.configId = ech.handle.configId
+
+	// Ask the ECH provider for the HPKE context.
+	if c.ech.opener == nil {
+		res := p.GetDecryptionContext(ech.handle.marshal(), extensionECH)
+
+		// Compute retry configurations, skipping those indicating an
+		// unsupported version.
+		if len(res.RetryConfigs) > 0 {
+			configs, err := UnmarshalECHConfigs(res.RetryConfigs) // skips unrecognized versions
+			if err != nil {
+				c.sendAlert(alertInternalError)
+				return nil, fmt.Errorf("ech: %s", err)
+			}
+
+			if len(configs) > 0 {
+				c.ech.retryConfigs, err = echMarshalConfigs(configs)
+				if err != nil {
+					c.sendAlert(alertInternalError)
+					return nil, fmt.Errorf("ech: %s", err)
+				}
+			}
+
+			// Check if the outer SNI matches the public name of any ECH config
+			// advertised by the client-facing server. As of
+			// draft-ietf-tls-esni-10, the client is required to use the ECH
+			// config's public name as the outer SNI. Although there's no real
+			// reason for the server to enforce this, it's worth noting it when
+			// it happens.
+			pubNameMatches := false
+			for _, config := range configs {
+				if hello.serverName == string(config.rawPublicName) {
+					pubNameMatches = true
+				}
+			}
+			if !pubNameMatches {
+				c.handleCFEvent(CFEventECHPublicNameMismatch{})
+			}
+		}
+
+		switch res.Status {
+		case ECHProviderSuccess:
+			c.ech.opener, err = hpke.UnmarshalOpener(res.Context)
+			if err != nil {
+				c.sendAlert(alertInternalError)
+				return nil, fmt.Errorf("ech: %s", err)
+			}
+		case ECHProviderReject:
+			// Reject ECH. We do not know at this point whether the client
+			// intended to offer or grease ECH, so we presume grease until the
+			// client indicates rejection by sending an "ech_required" alert.
+			c.ech.greased = true
+			return hello, nil
+		case ECHProviderAbort:
+			c.sendAlert(alert(res.Alert))
+			return nil, fmt.Errorf("ech: provider aborted: %s", res.Error)
+		default:
+			c.sendAlert(alertInternalError)
+			return nil, errors.New("ech: unexpected provider status")
+		}
+	}
+
+	// ClientHelloOuterAAD
+	rawHelloOuterAad := echEncodeClientHelloOuterAAD(hello.marshal(), uint(len(ech.payload)))
+	if rawHelloOuterAad == nil {
+		// This occurs if the ClientHelloOuter is malformed. This values was
+		// already parsed into `hello`, so this should not happen.
+		c.sendAlert(alertInternalError)
+		return nil, fmt.Errorf("ech: failed to encode ClientHelloOuterAAD")
+	}
+
+	// EncodedClientHelloInner
+	rawEncodedHelloInner, err := c.ech.opener.Open(ech.payload, rawHelloOuterAad)
+	if err != nil {
+		if afterHRR && c.ech.accepted {
+			// Don't reject after accept, as this would result in processing the
+			// ClientHelloOuter after processing the ClientHelloInner.
+			c.sendAlert(alertDecryptError)
+			return nil, fmt.Errorf("ech: hrr: reject after accept: %s", err)
+		}
+
+		// Reject ECH. We do not know at this point whether the client
+		// intended to offer or grease ECH, so we presume grease until the
+		// client indicates rejection by sending an "ech_required" alert.
+		c.ech.greased = true
+		return hello, nil
+	}
+
+	// ClientHelloInner
+	rawHelloInner := echDecodeClientHelloInner(rawEncodedHelloInner, hello.marshal(), hello.sessionId)
+	if rawHelloInner == nil {
+		c.sendAlert(alertIllegalParameter)
+		return nil, fmt.Errorf("ech: failed to decode EncodedClientHelloInner")
+	}
+	helloInner := new(clientHelloMsg)
+	if !helloInner.unmarshal(rawHelloInner) {
+		c.sendAlert(alertIllegalParameter)
+		return nil, fmt.Errorf("ech: failed to parse ClientHelloInner")
+	}
+
+	// Check for a well-formed ECH extension.
+	if len(helloInner.ech) != 1 ||
+		helloInner.ech[0] != echClientHelloInnerVariant {
+		c.sendAlert(alertIllegalParameter)
+		return nil, fmt.Errorf("ech: ClientHelloInner does not have a well-formed ECH extension")
+	}
+
+	// Check that the client did not offer TLS 1.2 or below in the inner
+	// handshake.
+	helloInnerSupportsTLS12OrBelow := len(helloInner.supportedVersions) == 0
+	for _, v := range helloInner.supportedVersions {
+		if v < VersionTLS13 {
+			helloInnerSupportsTLS12OrBelow = true
+		}
+	}
+	if helloInnerSupportsTLS12OrBelow {
+		c.sendAlert(alertIllegalParameter)
+		return nil, errors.New("ech: ClientHelloInner offers TLS 1.2 or below")
+	}
+
+	// Accept ECH.
+	c.ech.offered = true
+	c.ech.accepted = true
+	return helloInner, nil
+}
+
+// echClientOuter represents a ClientECH structure, the payload of the client's
+// "encrypted_client_hello" extension that appears in the outer handshake.
+type echClientOuter struct {
+	raw []byte
+
+	// Parsed from raw
+	handle  echContextHandle
+	payload []byte
+}
+
+// echUnmarshalClientOuter parses a ClientECH structure. The caller provides the
+// ECH version indicated by the client.
+func echUnmarshalClientOuter(raw []byte) (*echClientOuter, error) {
+	s := cryptobyte.String(raw)
+	ech := new(echClientOuter)
+	ech.raw = raw
+
+	// Make sure this is the outer handshake.
+	var variant uint8
+	if !s.ReadUint8(&variant) {
+		return nil, fmt.Errorf("error parsing ClientECH.type")
+	}
+	if variant != echClientHelloOuterVariant {
+		return nil, fmt.Errorf("unexpected ClientECH.type (want outer (0))")
+	}
+
+	// Parse the context handle.
+	if !echReadContextHandle(&s, &ech.handle) {
+		return nil, fmt.Errorf("error parsing context handle")
+	}
+	endOfContextHandle := len(raw) - len(s)
+	ech.handle.raw = raw[1:endOfContextHandle]
+
+	// Parse the payload.
+	var t cryptobyte.String
+	if !s.ReadUint16LengthPrefixed(&t) ||
+		!t.ReadBytes(&ech.payload, len(t)) || !s.Empty() {
+		return nil, fmt.Errorf("error parsing payload")
+	}
+
+	return ech, nil
+}
+
+func (ech *echClientOuter) marshal() []byte {
+	if ech.raw != nil {
+		return ech.raw
+	}
+	var b cryptobyte.Builder
+	b.AddUint8(echClientHelloOuterVariant)
+	b.AddBytes(ech.handle.marshal())
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(ech.payload)
+	})
+	return b.BytesOrPanic()
+}
+
+// echContextHandle represents the prefix of a ClientECH structure used by
+// the server to compute the HPKE context.
+type echContextHandle struct {
+	raw []byte
+
+	// Parsed from raw
+	suite    hpkeSymmetricCipherSuite
+	configId uint8
+	enc      []byte
+}
+
+func (handle *echContextHandle) marshal() []byte {
+	if handle.raw != nil {
+		return handle.raw
+	}
+	var b cryptobyte.Builder
+	b.AddUint16(handle.suite.kdfId)
+	b.AddUint16(handle.suite.aeadId)
+	b.AddUint8(handle.configId)
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(handle.enc)
+	})
+	return b.BytesOrPanic()
+}
+
+func echReadContextHandle(s *cryptobyte.String, handle *echContextHandle) bool {
+	var t cryptobyte.String
+	if !s.ReadUint16(&handle.suite.kdfId) || // cipher_suite.kdf_id
+		!s.ReadUint16(&handle.suite.aeadId) || // cipher_suite.aead_id
+		!s.ReadUint8(&handle.configId) || // config_id
+		!s.ReadUint16LengthPrefixed(&t) || // enc
+		!t.ReadBytes(&handle.enc, len(t)) {
+		return false
+	}
+	return true
+}
+
+// hpkeSymmetricCipherSuite represents an ECH ciphersuite, a KDF/AEAD algorithm pair. This
+// is different from an HPKE ciphersuite, which represents a KEM/KDF/AEAD
+// triple.
+type hpkeSymmetricCipherSuite struct {
+	kdfId, aeadId uint16
+}
+
+// Generates a grease ECH extension using a hard-coded KEM public key.
+func echGenerateGreaseExt(rand io.Reader) ([]byte, error) {
+	var err error
+	dummyX25519PublicKey := []byte{
+		143, 38, 37, 36, 12, 6, 229, 30, 140, 27, 167, 73, 26, 100, 203, 107, 216,
+		81, 163, 222, 52, 211, 54, 210, 46, 37, 78, 216, 157, 97, 241, 244,
+	}
+	dummyEncodedHelloInnerLen := 100 // TODO(cjpatton): Compute this correctly.
+	kem, kdf, aead := defaultHPKESuite.Params()
+
+	pk, err := kem.Scheme().UnmarshalBinaryPublicKey(dummyX25519PublicKey)
+	if err != nil {
+		return nil, fmt.Errorf("tls: grease ech: failed to parse dummy public key: %s", err)
+	}
+	sender, err := defaultHPKESuite.NewSender(pk, nil)
+	if err != nil {
+		return nil, fmt.Errorf("tls: grease ech: failed to create sender: %s", err)
+	}
+
+	var ech echClientOuter
+	ech.handle.suite.kdfId = uint16(kdf)
+	ech.handle.suite.aeadId = uint16(aead)
+	randomByte := make([]byte, 1)
+	_, err = io.ReadFull(rand, randomByte)
+	if err != nil {
+		return nil, fmt.Errorf("tls: grease ech: %s", err)
+	}
+	ech.handle.configId = randomByte[0]
+	ech.handle.enc, _, err = sender.Setup(rand)
+	if err != nil {
+		return nil, fmt.Errorf("tls: grease ech: %s", err)
+	}
+	ech.payload = make([]byte,
+		int(aead.CipherLen(uint(dummyEncodedHelloInnerLen))))
+	if _, err = io.ReadFull(rand, ech.payload); err != nil {
+		return nil, fmt.Errorf("tls: grease ech: %s", err)
+	}
+	return ech.marshal(), nil
+}
+
+// echEncodeClientHelloInner interprets innerData as a ClientHelloInner message
+// and transforms it into an EncodedClientHelloInner. Returns nil if parsing
+// innerData fails.
+func echEncodeClientHelloInner(innerData []byte, serverNameLen, maxNameLen int) []byte {
+	var (
+		errIllegalParameter      = errors.New("illegal parameter")
+		outerExtensions          = echOuterExtensions()
+		msgType                  uint8
+		legacyVersion            uint16
+		random                   []byte
+		legacySessionId          cryptobyte.String
+		cipherSuites             cryptobyte.String
+		legacyCompressionMethods cryptobyte.String
+		extensions               cryptobyte.String
+		s                        cryptobyte.String
+		b                        cryptobyte.Builder
+	)
+
+	u := cryptobyte.String(innerData)
+	if !u.ReadUint8(&msgType) ||
+		!u.ReadUint24LengthPrefixed(&s) || !u.Empty() {
+		return nil
+	}
+
+	if !s.ReadUint16(&legacyVersion) ||
+		!s.ReadBytes(&random, 32) ||
+		!s.ReadUint8LengthPrefixed(&legacySessionId) ||
+		!s.ReadUint16LengthPrefixed(&cipherSuites) ||
+		!s.ReadUint8LengthPrefixed(&legacyCompressionMethods) {
+		return nil
+	}
+
+	if s.Empty() {
+		// Extensions field must be present in TLS 1.3.
+		return nil
+	}
+
+	if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+		return nil
+	}
+
+	b.AddUint16(legacyVersion)
+	b.AddBytes(random)
+	b.AddUint8(0) // 0-length legacy_session_id
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(cipherSuites)
+	})
+	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(legacyCompressionMethods)
+	})
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		if testingECHOuterExtIncorrectOrder {
+			// Replace outer extensions with "outer_extension" extension, but in
+			// the incorrect order.
+			echAddOuterExtensions(b, outerExtensions)
+		}
+
+		for !extensions.Empty() {
+			var ext uint16
+			var extData cryptobyte.String
+			if !extensions.ReadUint16(&ext) ||
+				!extensions.ReadUint16LengthPrefixed(&extData) {
+				panic(cryptobyte.BuildError{Err: errIllegalParameter})
+			}
+
+			if len(outerExtensions) > 0 && ext == outerExtensions[0] {
+				if !testingECHOuterExtIncorrectOrder {
+					// Replace outer extensions with "outer_extension" extension.
+					echAddOuterExtensions(b, outerExtensions)
+				}
+
+				// Consume the remaining outer extensions.
+				for _, outerExt := range outerExtensions[1:] {
+					if !extensions.ReadUint16(&ext) ||
+						!extensions.ReadUint16LengthPrefixed(&extData) {
+						panic(cryptobyte.BuildError{Err: errIllegalParameter})
+					}
+					if ext != outerExt {
+						panic("internal error: malformed ClientHelloInner")
+					}
+				}
+
+			} else {
+				b.AddUint16(ext)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddBytes(extData)
+				})
+			}
+		}
+	})
+
+	encodedData, err := b.Bytes()
+	if err == errIllegalParameter {
+		return nil // Input malformed
+	} else if err != nil {
+		panic(err) // Host encountered internal error
+	}
+
+	// Add padding.
+	paddingLen := 0
+	if serverNameLen > 0 {
+		// draft-ietf-tls-esni-13, Section 6.1.3:
+		//
+		// If the ClientHelloInner contained a "server_name" extension with a
+		// name of length D, add max(0, L - D) bytes of padding.
+		if n := maxNameLen - serverNameLen; n > 0 {
+			paddingLen += n
+		}
+	} else {
+		// draft-ietf-tls-esni-13, Section 6.1.3:
+		//
+		// If the ClientHelloInner did not contain a "server_name" extension
+		// (e.g., if the client is connecting to an IP address), add L + 9 bytes
+		// of padding.  This is the length of a "server_name" extension with an
+		// L-byte name.
+		const sniPaddingLen = 9
+		paddingLen += sniPaddingLen + maxNameLen
+	}
+	paddingLen = 31 - ((len(encodedData) + paddingLen - 1) % 32)
+	for i := 0; i < paddingLen; i++ {
+		encodedData = append(encodedData, 0)
+	}
+
+	return encodedData
+}
+
+func echAddOuterExtensions(b *cryptobyte.Builder, outerExtensions []uint16) {
+	b.AddUint16(extensionECHOuterExtensions)
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			for _, outerExt := range outerExtensions {
+				b.AddUint16(outerExt)
+			}
+			if testingECHOuterExtIllegal {
+				// This is not allowed.
+				b.AddUint16(extensionECH)
+			}
+		})
+	})
+}
+
+// echDecodeClientHelloInner interprets encodedData as an EncodedClientHelloInner
+// message and substitutes the "outer_extension" extension with extensions from
+// outerData, interpreted as the ClientHelloOuter message. Returns nil if
+// parsing encodedData fails.
+func echDecodeClientHelloInner(encodedData, outerData, outerSessionId []byte) []byte {
+	var (
+		errIllegalParameter      = errors.New("illegal parameter")
+		legacyVersion            uint16
+		random                   []byte
+		legacySessionId          cryptobyte.String
+		cipherSuites             cryptobyte.String
+		legacyCompressionMethods cryptobyte.String
+		extensions               cryptobyte.String
+		b                        cryptobyte.Builder
+	)
+
+	s := cryptobyte.String(encodedData)
+	if !s.ReadUint16(&legacyVersion) ||
+		!s.ReadBytes(&random, 32) ||
+		!s.ReadUint8LengthPrefixed(&legacySessionId) ||
+		!s.ReadUint16LengthPrefixed(&cipherSuites) ||
+		!s.ReadUint8LengthPrefixed(&legacyCompressionMethods) {
+		return nil
+	}
+
+	if len(legacySessionId) > 0 {
+		return nil
+	}
+
+	if s.Empty() {
+		// Extensions field must be present in TLS 1.3.
+		return nil
+	}
+
+	if !s.ReadUint16LengthPrefixed(&extensions) {
+		return nil
+	}
+
+	b.AddUint8(typeClientHello)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint16(legacyVersion)
+		b.AddBytes(random)
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(outerSessionId) // ClientHelloOuter.legacy_session_id
+		})
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(cipherSuites)
+		})
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(legacyCompressionMethods)
+		})
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			var handledOuterExtensions bool
+			for !extensions.Empty() {
+				var ext uint16
+				var extData cryptobyte.String
+				if !extensions.ReadUint16(&ext) ||
+					!extensions.ReadUint16LengthPrefixed(&extData) {
+					panic(cryptobyte.BuildError{Err: errIllegalParameter})
+				}
+
+				if ext == extensionECHOuterExtensions {
+					if handledOuterExtensions {
+						// It is an error to send any extension more than once in a
+						// single message.
+						panic(cryptobyte.BuildError{Err: errIllegalParameter})
+					}
+					handledOuterExtensions = true
+
+					// Read the referenced outer extensions.
+					referencedExts := make([]uint16, 0, 10)
+					var outerExtData cryptobyte.String
+					if !extData.ReadUint8LengthPrefixed(&outerExtData) ||
+						len(outerExtData)%2 != 0 ||
+						!extData.Empty() {
+						panic(cryptobyte.BuildError{Err: errIllegalParameter})
+					}
+					for !outerExtData.Empty() {
+						if !outerExtData.ReadUint16(&ext) ||
+							ext == extensionECH {
+							panic(cryptobyte.BuildError{Err: errIllegalParameter})
+						}
+						referencedExts = append(referencedExts, ext)
+					}
+
+					// Add the outer extensions from the ClientHelloOuter into the
+					// ClientHelloInner.
+					outerCt := 0
+					r := processClientHelloExtensions(outerData, func(ext uint16, extData cryptobyte.String) bool {
+						if outerCt < len(referencedExts) && ext == referencedExts[outerCt] {
+							outerCt++
+							b.AddUint16(ext)
+							b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+								b.AddBytes(extData)
+							})
+						}
+						return true
+					})
+
+					// Ensure that all outer extensions have been incorporated
+					// exactly once, and in the correct order.
+					if !r || outerCt != len(referencedExts) {
+						panic(cryptobyte.BuildError{Err: errIllegalParameter})
+					}
+				} else {
+					b.AddUint16(ext)
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(extData)
+					})
+				}
+			}
+		})
+	})
+
+	innerData, err := b.Bytes()
+	if err == errIllegalParameter {
+		return nil // Input malformed
+	} else if err != nil {
+		panic(err) // Host encountered internal error
+	}
+
+	// Read the padding.
+	for !s.Empty() {
+		var zero uint8
+		if !s.ReadUint8(&zero) || zero != 0 {
+			return nil
+		}
+	}
+
+	return innerData
+}
+
+// echEncodeClientHelloOuterAAD interprets outerData as ClientHelloOuter and
+// constructs a ClientHelloOuterAAD. The output doesn't have the 4-byte prefix
+// that indicates the handshake message type and its length.
+func echEncodeClientHelloOuterAAD(outerData []byte, payloadLen uint) []byte {
+	var (
+		errIllegalParameter      = errors.New("illegal parameter")
+		msgType                  uint8
+		legacyVersion            uint16
+		random                   []byte
+		legacySessionId          cryptobyte.String
+		cipherSuites             cryptobyte.String
+		legacyCompressionMethods cryptobyte.String
+		extensions               cryptobyte.String
+		s                        cryptobyte.String
+		b                        cryptobyte.Builder
+	)
+
+	u := cryptobyte.String(outerData)
+	if !u.ReadUint8(&msgType) ||
+		!u.ReadUint24LengthPrefixed(&s) || !u.Empty() {
+		return nil
+	}
+
+	if !s.ReadUint16(&legacyVersion) ||
+		!s.ReadBytes(&random, 32) ||
+		!s.ReadUint8LengthPrefixed(&legacySessionId) ||
+		!s.ReadUint16LengthPrefixed(&cipherSuites) ||
+		!s.ReadUint8LengthPrefixed(&legacyCompressionMethods) {
+		return nil
+	}
+
+	if s.Empty() {
+		// Extensions field must be present in TLS 1.3.
+		return nil
+	}
+
+	if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+		return nil
+	}
+
+	b.AddUint16(legacyVersion)
+	b.AddBytes(random)
+	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(legacySessionId)
+	})
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(cipherSuites)
+	})
+	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(legacyCompressionMethods)
+	})
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		for !extensions.Empty() {
+			var ext uint16
+			var extData cryptobyte.String
+			if !extensions.ReadUint16(&ext) ||
+				!extensions.ReadUint16LengthPrefixed(&extData) {
+				panic(cryptobyte.BuildError{Err: errIllegalParameter})
+			}
+
+			// If this is the ECH extension and the payload is the outer variant
+			// of ClientECH, then replace the payloadLen 0 bytes.
+			if ext == extensionECH {
+				ech, err := echUnmarshalClientOuter(extData)
+				if err != nil {
+					panic(cryptobyte.BuildError{Err: errIllegalParameter})
+				}
+				ech.payload = make([]byte, payloadLen)
+				ech.raw = nil
+				extData = ech.marshal()
+			}
+
+			b.AddUint16(ext)
+			b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+				b.AddBytes(extData)
+			})
+		}
+	})
+
+	outerAadData, err := b.Bytes()
+	if err == errIllegalParameter {
+		return nil // Input malformed
+	} else if err != nil {
+		panic(err) // Host encountered internal error
+	}
+
+	return outerAadData
+}
+
+// echEncodeAcceptConfHelloRetryRequest interprets data as a ServerHello message
+// and replaces the payload of the ECH extension with 8 zero bytes. The output
+// includes the 4-byte prefix that indicates the message type and its length.
+func echEncodeAcceptConfHelloRetryRequest(data []byte) []byte {
+	var (
+		errIllegalParameter = errors.New("illegal parameter")
+		vers                uint16
+		random              []byte
+		sessionId           []byte
+		cipherSuite         uint16
+		compressionMethod   uint8
+		s                   cryptobyte.String
+		b                   cryptobyte.Builder
+	)
+
+	s = cryptobyte.String(data)
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint16(&vers) || !s.ReadBytes(&random, 32) ||
+		!readUint8LengthPrefixed(&s, &sessionId) ||
+		!s.ReadUint16(&cipherSuite) ||
+		!s.ReadUint8(&compressionMethod) {
+		return nil
+	}
+
+	if s.Empty() {
+		// ServerHello is optionally followed by extension data
+		return nil
+	}
+
+	var extensions cryptobyte.String
+	if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+		return nil
+	}
+
+	b.AddUint8(typeServerHello)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint16(vers)
+		b.AddBytes(random)
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(sessionId)
+		})
+		b.AddUint16(cipherSuite)
+		b.AddUint8(compressionMethod)
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			for !extensions.Empty() {
+				var extension uint16
+				var extData cryptobyte.String
+				if !extensions.ReadUint16(&extension) ||
+					!extensions.ReadUint16LengthPrefixed(&extData) {
+					panic(cryptobyte.BuildError{Err: errIllegalParameter})
+				}
+
+				b.AddUint16(extension)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					if extension == extensionECH {
+						b.AddBytes(zeros[:8])
+					} else {
+						b.AddBytes(extData)
+					}
+				})
+			}
+		})
+	})
+
+	encodedData, err := b.Bytes()
+	if err == errIllegalParameter {
+		return nil // Input malformed
+	} else if err != nil {
+		panic(err) // Host encountered internal error
+	}
+
+	return encodedData
+}
+
+// processClientHelloExtensions interprets data as a ClientHello and applies a
+// function proc to each extension. Returns a bool indicating whether parsing
+// succeeded.
+func processClientHelloExtensions(data []byte, proc func(ext uint16, extData cryptobyte.String) bool) bool {
+	_, extensionsData := splitClientHelloExtensions(data)
+	if extensionsData == nil {
+		return false
+	}
+
+	s := cryptobyte.String(extensionsData)
+	if s.Empty() {
+		// Extensions field not present.
+		return true
+	}
+
+	var extensions cryptobyte.String
+	if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+		return false
+	}
+
+	for !extensions.Empty() {
+		var ext uint16
+		var extData cryptobyte.String
+		if !extensions.ReadUint16(&ext) ||
+			!extensions.ReadUint16LengthPrefixed(&extData) {
+			return false
+		}
+		if ok := proc(ext, extData); !ok {
+			return false
+		}
+	}
+	return true
+}
+
+// splitClientHelloExtensions interprets data as a ClientHello message and
+// returns two strings: the first contains the start of the ClientHello up to
+// the start of the extensions; and the second is the length-prefixed
+// extensions. Returns (nil, nil) if parsing of data fails.
+func splitClientHelloExtensions(data []byte) ([]byte, []byte) {
+	s := cryptobyte.String(data)
+
+	var ignored uint16
+	var t cryptobyte.String
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint16(&ignored) || !s.Skip(32) || // vers, random
+		!s.ReadUint8LengthPrefixed(&t) { // session_id
+		return nil, nil
+	}
+
+	if !s.ReadUint16LengthPrefixed(&t) { // cipher_suites
+		return nil, nil
+	}
+
+	if !s.ReadUint8LengthPrefixed(&t) { // compression_methods
+		return nil, nil
+	}
+
+	return data[:len(data)-len(s)], s
+}
+
+// TODO(cjpatton): Handle public name as described in draft-ietf-tls-esni-13,
+// Section 4.
+//
+// TODO(cjpatton): Implement ECH config extensions as described in
+// draft-ietf-tls-esni-13, Section 4.1.
+func (c *Config) echSelectConfig() *ECHConfig {
+	for _, echConfig := range c.ClientECHConfigs {
+		if _, err := echConfig.selectSuite(); err == nil &&
+			echConfig.version == extensionECH {
+			return &echConfig
+		}
+	}
+	return nil
+}
+
+func (c *Config) echCanOffer() bool {
+	if c == nil {
+		return false
+	}
+	return c.ECHEnabled &&
+		c.echSelectConfig() != nil &&
+		c.maxSupportedVersion(roleClient) >= VersionTLS13
+}
+
+func (c *Config) echCanAccept() bool {
+	if c == nil {
+		return false
+	}
+	return c.ECHEnabled &&
+		c.ServerECHProvider != nil &&
+		c.maxSupportedVersion(roleServer) >= VersionTLS13
+}
+
+// echOuterExtensions returns the list of extensions of the ClientHelloOuter
+// that will be incorporated into the CleintHelloInner.
+func echOuterExtensions() []uint16 {
+	// NOTE(cjpatton): It would be nice to incorporate more extensions, but
+	// "key_share" is the last extension to appear in the ClientHello before
+	// "pre_shared_key". As a result, the only contiguous sequence of outer
+	// extensions that contains "key_share" is "key_share" itself. Note that
+	// we cannot change the order of extensions in the ClientHello, as the
+	// unit tests expect "key_share" to be the second to last extension.
+	outerExtensions := []uint16{extensionKeyShare}
+	if testingECHOuterExtMany {
+		// NOTE(cjpatton): Incorporating this particular sequence does not
+		// yield significant savings. However, it's useful to test that our
+		// server correctly handles a sequence of compressed extensions and
+		// not just one.
+		outerExtensions = []uint16{
+			extensionStatusRequest,
+			extensionSupportedCurves,
+			extensionSupportedPoints,
+		}
+	} else if testingECHOuterExtNone {
+		outerExtensions = []uint16{}
+	}
+
+	return outerExtensions
+}
+
+func echCopyExtensionFromClientHelloInner(hello, helloInner *clientHelloMsg, ext uint16) {
+	switch ext {
+	case extensionStatusRequest:
+		hello.ocspStapling = helloInner.ocspStapling
+	case extensionSupportedCurves:
+		hello.supportedCurves = helloInner.supportedCurves
+	case extensionSupportedPoints:
+		hello.supportedPoints = helloInner.supportedPoints
+	case extensionKeyShare:
+		hello.keyShares = helloInner.keyShares
+	default:
+		panic(fmt.Errorf("tried to copy unrecognized extension: %04x", ext))
+	}
+}

+ 164 - 0
transport/cloudflaretls/ech_config.go

@@ -0,0 +1,164 @@
+// Copyright 2020 Cloudflare, Inc. All rights reserved. Use of this source code
+// is governed by a BSD-style license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"errors"
+	"fmt"
+	"io"
+
+	"github.com/cloudflare/circl/hpke"
+	"github.com/cloudflare/circl/kem"
+	"golang.org/x/crypto/cryptobyte"
+)
+
+// ECHConfig represents an ECH configuration.
+type ECHConfig struct {
+	pk  kem.PublicKey
+	raw []byte
+
+	// Parsed from raw
+	version           uint16
+	configId          uint8
+	rawPublicName     []byte
+	rawPublicKey      []byte
+	kemId             uint16
+	suites            []hpkeSymmetricCipherSuite
+	maxNameLen        uint8
+	ignoredExtensions []byte
+}
+
+// UnmarshalECHConfigs parses a sequence of ECH configurations.
+func UnmarshalECHConfigs(raw []byte) ([]ECHConfig, error) {
+	var (
+		err         error
+		config      ECHConfig
+		t, contents cryptobyte.String
+	)
+	configs := make([]ECHConfig, 0)
+	s := cryptobyte.String(raw)
+	if !s.ReadUint16LengthPrefixed(&t) || !s.Empty() {
+		return configs, errors.New("error parsing configs")
+	}
+	raw = raw[2:]
+ConfigsLoop:
+	for !t.Empty() {
+		l := len(t)
+		if !t.ReadUint16(&config.version) ||
+			!t.ReadUint16LengthPrefixed(&contents) {
+			return nil, errors.New("error parsing config")
+		}
+		n := l - len(t)
+		config.raw = raw[:n]
+		raw = raw[n:]
+
+		if config.version != extensionECH {
+			continue ConfigsLoop
+		}
+		if !readConfigContents(&contents, &config) {
+			return nil, errors.New("error parsing config contents")
+		}
+
+		kem := hpke.KEM(config.kemId)
+		if !kem.IsValid() {
+			continue ConfigsLoop
+		}
+		config.pk, err = kem.Scheme().UnmarshalBinaryPublicKey(config.rawPublicKey)
+		if err != nil {
+			return nil, fmt.Errorf("error parsing public key: %s", err)
+		}
+		configs = append(configs, config)
+	}
+	return configs, nil
+}
+
+func echMarshalConfigs(configs []ECHConfig) ([]byte, error) {
+	var b cryptobyte.Builder
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		for _, config := range configs {
+			if config.raw == nil {
+				panic("config.raw not set")
+			}
+			b.AddBytes(config.raw)
+		}
+	})
+	return b.Bytes()
+}
+
+func readConfigContents(contents *cryptobyte.String, config *ECHConfig) bool {
+	var t cryptobyte.String
+	if !contents.ReadUint8(&config.configId) ||
+		!contents.ReadUint16(&config.kemId) ||
+		!contents.ReadUint16LengthPrefixed(&t) ||
+		!t.ReadBytes(&config.rawPublicKey, len(t)) ||
+		!contents.ReadUint16LengthPrefixed(&t) ||
+		len(t)%4 != 0 {
+		return false
+	}
+
+	config.suites = nil
+	for !t.Empty() {
+		var kdfId, aeadId uint16
+		if !t.ReadUint16(&kdfId) || !t.ReadUint16(&aeadId) {
+			// This indicates an internal bug.
+			panic("internal error while parsing contents.cipher_suites")
+		}
+		config.suites = append(config.suites, hpkeSymmetricCipherSuite{kdfId, aeadId})
+	}
+
+	if !contents.ReadUint8(&config.maxNameLen) ||
+		!contents.ReadUint8LengthPrefixed(&t) ||
+		!t.ReadBytes(&config.rawPublicName, len(t)) ||
+		!contents.ReadUint16LengthPrefixed(&t) ||
+		!t.ReadBytes(&config.ignoredExtensions, len(t)) ||
+		!contents.Empty() {
+		return false
+	}
+	return true
+}
+
+// setupSealer generates the client's HPKE context for use with the ECH
+// extension. It returns the context and corresponding encapsulated key.
+func (config *ECHConfig) setupSealer(rand io.Reader) (enc []byte, sealer hpke.Sealer, err error) {
+	if config.raw == nil {
+		panic("config.raw not set")
+	}
+	hpkeSuite, err := config.selectSuite()
+	if err != nil {
+		return nil, nil, err
+	}
+	info := append(append([]byte(echHpkeInfoSetup), 0), config.raw...)
+	sender, err := hpkeSuite.NewSender(config.pk, info)
+	if err != nil {
+		return nil, nil, err
+	}
+	return sender.Setup(rand)
+}
+
+// isPeerCipherSuiteSupported returns true if this configuration indicates
+// support for the given ciphersuite.
+func (config *ECHConfig) isPeerCipherSuiteSupported(suite hpkeSymmetricCipherSuite) bool {
+	for _, configSuite := range config.suites {
+		if suite == configSuite {
+			return true
+		}
+	}
+	return false
+}
+
+// selectSuite returns the first ciphersuite indicated by this
+// configuration that is supported by the caller.
+func (config *ECHConfig) selectSuite() (hpke.Suite, error) {
+	for _, suite := range config.suites {
+		hpkeSuite, err := hpkeAssembleSuite(
+			config.kemId,
+			suite.kdfId,
+			suite.aeadId,
+		)
+		if err == nil {
+			return hpkeSuite, nil
+		}
+	}
+	return hpke.Suite{}, errors.New("could not negotiate a ciphersuite")
+}

+ 302 - 0
transport/cloudflaretls/ech_provider.go

@@ -0,0 +1,302 @@
+// Copyright 2020 Cloudflare, Inc. All rights reserved. Use of this source code
+// is governed by a BSD-style license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/cloudflare/circl/hpke"
+	"github.com/cloudflare/circl/kem"
+	"golang.org/x/crypto/cryptobyte"
+)
+
+// ECHProvider specifies the interface of an ECH service provider that decrypts
+// the ECH payload on behalf of the client-facing server. It also defines the
+// set of acceptable ECH configurations.
+type ECHProvider interface {
+	// GetDecryptionContext attempts to construct the HPKE context used by the
+	// client-facing server for decryption. (See draft-irtf-cfrg-hpke-07,
+	// Section 5.2.)
+	//
+	// handle encodes the parameters of the client's "encrypted_client_hello"
+	// extension that are needed to construct the context. Since
+	// draft-ietf-tls-esni-10 these are the ECH cipher suite, the identity of
+	// the ECH configuration, and the encapsulated key.
+	//
+	// version is the version of ECH indicated by the client.
+	//
+	// res.Status == ECHProviderStatusSuccess indicates the call was successful
+	// and the caller may proceed. res.Context is set.
+	//
+	// res.Status == ECHProviderStatusReject indicates the caller must reject
+	// ECH. res.RetryConfigs may be set.
+	//
+	// res.Status == ECHProviderStatusAbort indicates the caller should abort
+	// the handshake.  Note that, in some cases, it's appropriate to reject
+	// rather than abort. In particular, aborting with "illegal_parameter" might
+	// "stick out". res.Alert and res.Error are set.
+	GetDecryptionContext(handle []byte, version uint16) (res ECHProviderResult)
+}
+
+// ECHProviderStatus is the status of the ECH provider's response.
+type ECHProviderStatus uint
+
+const (
+	ECHProviderSuccess ECHProviderStatus = 0
+	ECHProviderReject                    = 1
+	ECHProviderAbort                     = 2
+
+	errHPKEInvalidPublicKey = "hpke: invalid KEM public key"
+)
+
+// ECHProviderResult represents the result of invoking the ECH provider.
+type ECHProviderResult struct {
+	Status ECHProviderStatus
+
+	// Alert is the TLS alert sent by the caller when aborting the handshake.
+	Alert uint8
+
+	// Error is the error propagated by the caller when aborting the handshake.
+	Error error
+
+	// RetryConfigs is the sequence of ECH configs to offer to the client for
+	// retrying the handshake. This may be set in case of success or rejection.
+	RetryConfigs []byte
+
+	// Context is the server's HPKE context. This is set if ECH is not rejected
+	// by the provider and no error was reported. The data has the following
+	// format (in TLS syntax):
+	//
+	// enum { sealer(0), opener(1) } HpkeRole;
+	//
+	// struct {
+	//     HpkeRole role;
+	//     HpkeKemId kem_id;   // as defined in draft-irtf-cfrg-hpke-07
+	//     HpkeKdfId kdf_id;   // as defined in draft-irtf-cfrg-hpke-07
+	//     HpkeAeadId aead_id; // as defined in draft-irtf-cfrg-hpke-07
+	//     opaque exporter_secret<0..255>;
+	//     opaque key<0..255>;
+	//     opaque base_nonce<0..255>;
+	//     opaque seq<0..255>;
+	// } HpkeContext;
+	Context []byte
+}
+
+// EXP_ECHKeySet implements the ECHProvider interface for a sequence of ECH keys.
+//
+// NOTE: This API is EXPERIMENTAL and subject to change.
+type EXP_ECHKeySet struct {
+	// The serialized ECHConfigs, in order of the server's preference.
+	configs []byte
+
+	// Maps a configuration identifier to its secret key.
+	sk map[uint8]EXP_ECHKey
+}
+
+// EXP_NewECHKeySet constructs an EXP_ECHKeySet.
+func EXP_NewECHKeySet(keys []EXP_ECHKey) (*EXP_ECHKeySet, error) {
+	if len(keys) > 255 {
+		return nil, fmt.Errorf("tls: ech provider: unable to support more than 255 ECH configurations at once")
+	}
+
+	keySet := new(EXP_ECHKeySet)
+	keySet.sk = make(map[uint8]EXP_ECHKey)
+	configs := make([]byte, 0)
+	for _, key := range keys {
+		if _, ok := keySet.sk[key.config.configId]; ok {
+			return nil, fmt.Errorf("tls: ech provider: ECH config conflict for configId %d", key.config.configId)
+		}
+
+		keySet.sk[key.config.configId] = key
+		configs = append(configs, key.config.raw...)
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(configs)
+	})
+	keySet.configs = b.BytesOrPanic()
+
+	return keySet, nil
+}
+
+// GetDecryptionContext is required by the ECHProvider interface.
+func (keySet *EXP_ECHKeySet) GetDecryptionContext(rawHandle []byte, version uint16) (res ECHProviderResult) {
+	// Propagate retry configurations regardless of the result. The caller sends
+	// these to the clients only if it rejects.
+	res.RetryConfigs = keySet.configs
+
+	// Ensure we know how to proceed, i.e., the caller has indicated a supported
+	// version of ECH. Currently only draft-ietf-tls-esni-13 is supported.
+	if version != extensionECH {
+		res.Status = ECHProviderAbort
+		res.Alert = uint8(alertInternalError)
+		res.Error = errors.New("version not supported")
+		return // Abort
+	}
+
+	// Parse the handle.
+	s := cryptobyte.String(rawHandle)
+	handle := new(echContextHandle)
+	if !echReadContextHandle(&s, handle) || !s.Empty() {
+		// This is the result of a client-side error. However, aborting with
+		// "illegal_parameter" would stick out, so we reject instead.
+		res.Status = ECHProviderReject
+		res.RetryConfigs = keySet.configs
+		return // Reject
+	}
+	handle.raw = rawHandle
+
+	// Look up the secret key for the configuration indicated by the client.
+	key, ok := keySet.sk[handle.configId]
+	if !ok {
+		res.Status = ECHProviderReject
+		res.RetryConfigs = keySet.configs
+		return // Reject
+	}
+
+	// Ensure that support for the selected ciphersuite is indicated by the
+	// configuration.
+	suite := handle.suite
+	if !key.config.isPeerCipherSuiteSupported(suite) {
+		// This is the result of a client-side error. However, aborting with
+		// "illegal_parameter" would stick out, so we reject instead.
+		res.Status = ECHProviderReject
+		res.RetryConfigs = keySet.configs
+		return // Reject
+	}
+
+	// Ensure the version indicated by the client matches the version supported
+	// by the configuration.
+	if version != key.config.version {
+		// This is the result of a client-side error. However, aborting with
+		// "illegal_parameter" would stick out, so we reject instead.
+		res.Status = ECHProviderReject
+		res.RetryConfigs = keySet.configs
+		return // Reject
+	}
+
+	// Compute the decryption context.
+	opener, err := key.setupOpener(handle.enc, suite)
+	if err != nil {
+		if err.Error() == errHPKEInvalidPublicKey {
+			// This occurs if the KEM algorithm used to generate handle.enc is
+			// not the same as the KEM algorithm of the key. One way this can
+			// happen is if the client sent a GREASE ECH extension with a
+			// config_id that happens to match a known config, but which uses a
+			// different KEM algorithm.
+			res.Status = ECHProviderReject
+			res.RetryConfigs = keySet.configs
+			return // Reject
+		}
+
+		res.Status = ECHProviderAbort
+		res.Alert = uint8(alertInternalError)
+		res.Error = err
+		return // Abort
+	}
+
+	// Serialize the decryption context.
+	res.Context, err = opener.MarshalBinary()
+	if err != nil {
+		res.Status = ECHProviderAbort
+		res.Alert = uint8(alertInternalError)
+		res.Error = err
+		return // Abort
+	}
+
+	res.Status = ECHProviderSuccess
+	return // Success
+}
+
+// EXP_ECHKey represents an ECH key and its corresponding configuration. The
+// encoding of an ECH Key has the format defined below (in TLS syntax). Note
+// that the ECH standard does not specify this format.
+//
+//	struct {
+//	    opaque sk<0..2^16-1>;
+//	    ECHConfig config<0..2^16>; // draft-ietf-tls-esni-13
+//	} ECHKey;
+type EXP_ECHKey struct {
+	sk     kem.PrivateKey
+	config ECHConfig
+}
+
+// EXP_UnmarshalECHKeys parses a sequence of ECH keys.
+func EXP_UnmarshalECHKeys(raw []byte) ([]EXP_ECHKey, error) {
+	var (
+		err                  error
+		key                  EXP_ECHKey
+		sk, config, contents cryptobyte.String
+	)
+	s := cryptobyte.String(raw)
+	keys := make([]EXP_ECHKey, 0)
+KeysLoop:
+	for !s.Empty() {
+		if !s.ReadUint16LengthPrefixed(&sk) ||
+			!s.ReadUint16LengthPrefixed(&config) {
+			return nil, errors.New("error parsing key")
+		}
+
+		key.config.raw = config
+		if !config.ReadUint16(&key.config.version) ||
+			!config.ReadUint16LengthPrefixed(&contents) ||
+			!config.Empty() {
+			return nil, errors.New("error parsing config")
+		}
+
+		if key.config.version != extensionECH {
+			continue KeysLoop
+		}
+		if !readConfigContents(&contents, &key.config) {
+			return nil, errors.New("error parsing config contents")
+		}
+
+		for _, suite := range key.config.suites {
+			if !hpke.KDF(suite.kdfId).IsValid() ||
+				!hpke.AEAD(suite.aeadId).IsValid() {
+				continue KeysLoop
+			}
+		}
+
+		kem := hpke.KEM(key.config.kemId)
+		if !kem.IsValid() {
+			continue KeysLoop
+		}
+		key.config.pk, err = kem.Scheme().UnmarshalBinaryPublicKey(key.config.rawPublicKey)
+		if err != nil {
+			return nil, fmt.Errorf("error parsing public key: %s", err)
+		}
+		key.sk, err = kem.Scheme().UnmarshalBinaryPrivateKey(sk)
+		if err != nil {
+			return nil, fmt.Errorf("error parsing secret key: %s", err)
+		}
+
+		keys = append(keys, key)
+	}
+	return keys, nil
+}
+
+// setupOpener computes the HPKE context used by the server in the ECH
+// extension.i
+func (key *EXP_ECHKey) setupOpener(enc []byte, suite hpkeSymmetricCipherSuite) (hpke.Opener, error) {
+	if key.config.raw == nil {
+		panic("raw config not set")
+	}
+	hpkeSuite, err := hpkeAssembleSuite(
+		key.config.kemId,
+		suite.kdfId,
+		suite.aeadId,
+	)
+	if err != nil {
+		return nil, err
+	}
+	info := append(append([]byte(echHpkeInfoSetup), 0), key.config.raw...)
+	receiver, err := hpkeSuite.NewReceiver(key.sk, info)
+	if err != nil {
+		return nil, err
+	}
+	return receiver.Setup(enc)
+}

+ 194 - 0
transport/cloudflaretls/generate_cert.go

@@ -0,0 +1,194 @@
+// 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.
+
+//go:build ignore
+
+// Generate a self-signed X.509 certificate for a TLS server. Outputs to
+// 'cert.pem' and 'key.pem' and will overwrite existing files.
+
+package main
+
+import (
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/elliptic"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"flag"
+	"log"
+	"math/big"
+	"net"
+	"os"
+	"strings"
+	"time"
+
+	circlSign "github.com/cloudflare/circl/sign"
+	circlSchemes "github.com/cloudflare/circl/sign/schemes"
+)
+
+var (
+	host       = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for")
+	validFrom  = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
+	validFor   = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
+	isCA       = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
+	allowDC    = flag.Bool("allowDC", false, "whether this cert can be used with Delegated Credentials")
+	rsaBits    = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set")
+	ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521")
+	ed25519Key = flag.Bool("ed25519", false, "Generate an Ed25519 key")
+	circlKey   = flag.String("github.com/cloudflare/circl", "", "Generate a key supported by Circl")
+)
+
+func publicKey(priv any) any {
+	switch k := priv.(type) {
+	case *rsa.PrivateKey:
+		return &k.PublicKey
+	case *ecdsa.PrivateKey:
+		return &k.PublicKey
+	case ed25519.PrivateKey:
+		return k.Public().(ed25519.PublicKey)
+	case circlSign.PrivateKey:
+		return k.Public()
+	default:
+		return nil
+	}
+}
+
+func main() {
+	flag.Parse()
+
+	if len(*host) == 0 {
+		log.Fatalf("Missing required --host parameter")
+	}
+
+	var priv any
+	var err error
+	switch *ecdsaCurve {
+	case "":
+		if *ed25519Key {
+			_, priv, err = ed25519.GenerateKey(rand.Reader)
+		} else if *circlKey != "" {
+			scheme := circlSchemes.ByName(*circlKey)
+			if scheme == nil {
+				log.Fatalf("No such Circl scheme: %s", *circlKey)
+			}
+			_, priv, err = scheme.GenerateKey()
+		} else {
+			priv, err = rsa.GenerateKey(rand.Reader, *rsaBits)
+		}
+	case "P224":
+		priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
+	case "P256":
+		priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	case "P384":
+		priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+	case "P521":
+		priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+	default:
+		log.Fatalf("Unrecognized elliptic curve: %q", *ecdsaCurve)
+	}
+	if err != nil {
+		log.Fatalf("Failed to generate private key: %v", err)
+	}
+
+	// ECDSA, ED25519 and RSA subject keys should have the DigitalSignature
+	// KeyUsage bits set in the x509.Certificate template
+	keyUsage := x509.KeyUsageDigitalSignature
+	// Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In
+	// the context of TLS this KeyUsage is particular to RSA key exchange and
+	// authentication.
+	if _, isRSA := priv.(*rsa.PrivateKey); isRSA {
+		keyUsage |= x509.KeyUsageKeyEncipherment
+	}
+
+	var notBefore time.Time
+	if len(*validFrom) == 0 {
+		notBefore = time.Now()
+	} else {
+		notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom)
+		if err != nil {
+			log.Fatalf("Failed to parse creation date: %v", err)
+		}
+	}
+
+	notAfter := notBefore.Add(*validFor)
+
+	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+	if err != nil {
+		log.Fatalf("Failed to generate serial number: %v", err)
+	}
+
+	template := x509.Certificate{
+		SerialNumber: serialNumber,
+		Subject: pkix.Name{
+			Organization: []string{"Acme Co"},
+		},
+		NotBefore: notBefore,
+		NotAfter:  notAfter,
+
+		KeyUsage:              keyUsage,
+		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+		BasicConstraintsValid: true,
+	}
+
+	hosts := strings.Split(*host, ",")
+	for _, h := range hosts {
+		if ip := net.ParseIP(h); ip != nil {
+			template.IPAddresses = append(template.IPAddresses, ip)
+		} else {
+			template.DNSNames = append(template.DNSNames, h)
+		}
+	}
+
+	if *isCA {
+		if *allowDC {
+			log.Fatal("Failed to create certificate: ca is not allowed with the dc flag")
+		}
+
+		template.IsCA = true
+		template.KeyUsage |= x509.KeyUsageCertSign
+	}
+
+	if *allowDC {
+		template.AllowDC = true
+		template.KeyUsage |= x509.KeyUsageDigitalSignature
+	}
+
+	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
+	if err != nil {
+		log.Fatalf("Failed to create certificate: %v", err)
+	}
+
+	certOut, err := os.Create("cert.pem")
+	if err != nil {
+		log.Fatalf("Failed to open cert.pem for writing: %v", err)
+	}
+	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
+		log.Fatalf("Failed to write data to cert.pem: %v", err)
+	}
+	if err := certOut.Close(); err != nil {
+		log.Fatalf("Error closing cert.pem: %v", err)
+	}
+	log.Print("wrote cert.pem\n")
+
+	keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
+	if err != nil {
+		log.Fatalf("Failed to open key.pem for writing: %v", err)
+		return
+	}
+	privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
+	if err != nil {
+		log.Fatalf("Unable to marshal private key: %v", err)
+	}
+	if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
+		log.Fatalf("Failed to write data to key.pem: %v", err)
+	}
+	if err := keyOut.Close(); err != nil {
+		log.Fatalf("Error closing key.pem: %v", err)
+	}
+	log.Print("wrote key.pem\n")
+}

+ 126 - 0
transport/cloudflaretls/generate_delegated_credential.go

@@ -0,0 +1,126 @@
+// Copyright 2022 Cloudflare, Inc. All rights reserved. Use of this source code
+// is governed by a BSD-style license that can be found in the LICENSE file.
+
+//go:build ignore
+
+// Generate a delegated credential with the given signature scheme, signed with
+// the given x.509 key pair. Outputs to 'dc.cred' and 'dckey.pem' and will
+// overwrite existing files.
+
+// Example usage:
+// generate_delegated_credential -cert-path cert.pem -key-path key.pem -signature-scheme Ed25519 -duration 24h
+
+package main
+
+import (
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/rsa"
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"time"
+
+	circlSign "github.com/cloudflare/circl/sign"
+)
+
+var (
+	validFor        = flag.Duration("duration", 5*24*time.Hour, "Duration that credential is valid for")
+	signatureScheme = flag.String("signature-scheme", "", "The signature scheme used by the DC")
+	certPath        = flag.String("cert-path", "./cert.pem", "Path to signing cert")
+	keyPath         = flag.String("key-path", "./key.pem", "Path to signing key")
+	isClient        = flag.Bool("client-dc", false, "Create a client Delegated Credential")
+	outPath         = flag.String("out-path", "./", "Path to output directory")
+)
+
+var SigStringMap = map[string]tls.SignatureScheme{
+	// ECDSA algorithms. Only constrained to a specific curve in TLS 1.3.
+	"ECDSAWithP256AndSHA256": tls.ECDSAWithP256AndSHA256,
+	"ECDSAWithP384AndSHA384": tls.ECDSAWithP384AndSHA384,
+	"ECDSAWithP521AndSHA512": tls.ECDSAWithP521AndSHA512,
+
+	// EdDSA algorithms.
+	"Ed25519": tls.Ed25519,
+}
+
+func main() {
+	flag.Parse()
+	sa := SigStringMap[*signatureScheme]
+
+	cert, err := tls.LoadX509KeyPair(*certPath, *keyPath)
+	if err != nil {
+		log.Fatalf("Failed to load certificate and key: %v", err)
+	}
+	cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
+	if err != nil {
+		log.Fatalf("Failed to parse leaf certificate: %v", err)
+	}
+
+	validTime := time.Since(cert.Leaf.NotBefore) + *validFor
+	dc, priv, err := tls.NewDelegatedCredential(&cert, sa, validTime, *isClient)
+	if err != nil {
+		log.Fatalf("Failed to create a DC: %v\n", err)
+	}
+	dcBytes, err := dc.Marshal()
+	if err != nil {
+		log.Fatalf("Failed to marshal DC: %v\n", err)
+	}
+
+	DCOut, err := os.Create(filepath.Join(*outPath, "dc.cred"))
+	if err != nil {
+		log.Fatalf("Failed to open dc.cred for writing: %v", err)
+	}
+
+	DCOut.Write(dcBytes)
+	if err := DCOut.Close(); err != nil {
+		log.Fatalf("Error closing dc.cred: %v", err)
+	}
+	log.Print("wrote dc.cred\n")
+
+	derBytes, err := x509.MarshalPKCS8PrivateKey(priv)
+	if err != nil {
+		log.Fatalf("Failed to marshal DC private key: %v\n", err)
+	}
+
+	DCKeyOut, err := os.Create(filepath.Join(*outPath, "dckey.pem"))
+	if err != nil {
+		log.Fatalf("Failed to open dckey.pem for writing: %v", err)
+	}
+
+	if err := pem.Encode(DCKeyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: derBytes}); err != nil {
+		log.Fatalf("Failed to write data to dckey.pem: %v\n", err)
+	}
+	if err := DCKeyOut.Close(); err != nil {
+		log.Fatalf("Error closing dckey.pem: %v\n", err)
+	}
+	log.Print("wrote dckey.pem\n")
+
+	fmt.Println("Success")
+}
+
+// Copied from tls.go, because it's private.
+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, circlSign.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")
+}

+ 1069 - 0
transport/cloudflaretls/handshake_client.go

@@ -0,0 +1,1069 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"bytes"
+	"context"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/rsa"
+	"crypto/subtle"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"hash"
+	"io"
+	"net"
+	"strings"
+	"sync/atomic"
+	"time"
+
+	circlSign "github.com/cloudflare/circl/sign"
+)
+
+type clientHandshakeState struct {
+	c            *Conn
+	ctx          context.Context
+	serverHello  *serverHelloMsg
+	hello        *clientHelloMsg
+	suite        *cipherSuite
+	finishedHash finishedHash
+	masterSecret []byte
+	session      *ClientSessionState
+}
+
+func (c *Conn) makeClientHello(minVersion uint16) (*clientHelloMsg, clientKeySharePrivate, error) {
+	config := c.config
+	if len(config.ServerName) == 0 && !config.InsecureSkipVerify {
+		return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
+	}
+
+	nextProtosLength := 0
+	for _, proto := range config.NextProtos {
+		if l := len(proto); l == 0 || l > 255 {
+			return nil, nil, errors.New("tls: invalid NextProtos value")
+		} else {
+			nextProtosLength += 1 + l
+		}
+	}
+	if nextProtosLength > 0xffff {
+		return nil, nil, errors.New("tls: NextProtos values too large")
+	}
+
+	supportedVersions := config.supportedVersionsFromMin(roleClient, minVersion)
+	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.
+	if clientHelloVersion > VersionTLS12 {
+		clientHelloVersion = VersionTLS12
+	}
+
+	hello := &clientHelloMsg{
+		vers:                         clientHelloVersion,
+		compressionMethods:           []uint8{compressionNone},
+		random:                       make([]byte, 32),
+		sessionId:                    make([]byte, 32),
+		ocspStapling:                 true,
+		scts:                         true,
+		serverName:                   hostnameInSNI(config.ServerName),
+		supportedCurves:              config.curvePreferences(),
+		supportedPoints:              []uint8{pointFormatUncompressed},
+		secureRenegotiationSupported: true,
+		alpnProtocols:                config.NextProtos,
+		supportedVersions:            supportedVersions,
+	}
+
+	if c.handshakes > 0 {
+		hello.secureRenegotiation = c.clientFinished[:]
+	}
+
+	preferenceOrder := cipherSuitesPreferenceOrder
+	if !hasAESGCMHardwareSupport {
+		preferenceOrder = cipherSuitesPreferenceOrderNoAES
+	}
+	configCipherSuites := config.cipherSuites()
+	hello.cipherSuites = make([]uint16, 0, len(configCipherSuites))
+
+	for _, suiteId := range preferenceOrder {
+		suite := mutualCipherSuite(configCipherSuites, suiteId)
+		if suite == nil {
+			continue
+		}
+		// Don't advertise TLS 1.2-only cipher suites unless
+		// we're attempting TLS 1.2.
+		if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
+			continue
+		}
+		hello.cipherSuites = append(hello.cipherSuites, suiteId)
+	}
+
+	_, err := io.ReadFull(config.rand(), hello.random)
+	if err != nil {
+		return nil, nil, errors.New("tls: short read from Rand: " + err.Error())
+	}
+
+	// A random session ID is used to detect when the server accepted a ticket
+	// and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as
+	// a compatibility measure (see RFC 8446, Section 4.1.2).
+	if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil {
+		return nil, nil, errors.New("tls: short read from Rand: " + err.Error())
+	}
+
+	if hello.vers >= VersionTLS12 {
+		hello.supportedSignatureAlgorithms = config.supportedSignatureAlgorithms()
+	}
+
+	var secret clientKeySharePrivate
+	if hello.supportedVersions[0] == VersionTLS13 {
+		if hasAESGCMHardwareSupport {
+			hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
+		} else {
+			hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
+		}
+
+		curveID := config.curvePreferences()[0]
+		if scheme := curveIdToCirclScheme(curveID); scheme != nil {
+			pk, sk, err := generateKemKeyPair(scheme, config.rand())
+			if err != nil {
+				return nil, nil, fmt.Errorf("generateKemKeyPair %s: %w",
+					scheme.Name(), err)
+			}
+			packedPk, err := pk.MarshalBinary()
+			if err != nil {
+				return nil, nil, fmt.Errorf("pack circl public key %s: %w",
+					scheme.Name(), err)
+			}
+			hello.keyShares = []keyShare{{group: curveID, data: packedPk}}
+			secret = sk
+		} else {
+			if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
+				return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
+			}
+			params, err := generateECDHEParameters(config.rand(), curveID)
+			if err != nil {
+				return nil, nil, err
+			}
+			hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
+			secret = params
+		}
+
+		hello.delegatedCredentialSupported = config.SupportDelegatedCredential
+		hello.supportedSignatureAlgorithmsDC = supportedSignatureAlgorithmsDC
+	}
+
+	return hello, secret, nil
+}
+
+func (c *Conn) clientHandshake(ctx context.Context) (err error) {
+	if c.config == nil {
+		c.config = defaultConfig()
+	}
+
+	hsTimings := createTLS13ClientHandshakeTimingInfo(c.config.Time)
+
+	// This may be a renegotiation handshake, in which case some fields
+	// need to be reset.
+	c.didResume = false
+
+	// Determine the minimum required version for this handshake.
+	minVersion := c.config.MinVersion
+	if c.config.echCanOffer() {
+		// If the ECH extension will be offered in this handshake, then the
+		// ClientHelloInner must not offer TLS 1.2 or below.
+		minVersion = VersionTLS13
+	}
+
+	helloBase, ecdheParams, err := c.makeClientHello(minVersion)
+	if err != nil {
+		return err
+	}
+
+	hello, helloInner, err := c.echOfferOrGrease(helloBase)
+	if err != nil {
+		return err
+	}
+
+	helloResumed := hello
+	if c.ech.offered {
+		helloResumed = helloInner
+	}
+
+	cacheKey, session, earlySecret, binderKey := c.loadSession(helloResumed)
+	if cacheKey != "" && session != nil {
+		defer func() {
+			// If we got a handshake failure when resuming a session, throw away
+			// the session ticket. See RFC 5077, Section 3.2.
+			//
+			// RFC 8446 makes no mention of dropping tickets on failure, but it
+			// does require servers to abort on invalid binders, so we need to
+			// delete tickets to recover from a corrupted PSK.
+			if err != nil {
+				c.config.ClientSessionCache.Put(cacheKey, nil)
+			}
+		}()
+	}
+
+	if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil {
+		return err
+	}
+
+	hsTimings.WriteClientHello = hsTimings.elapsedTime()
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	serverHello, ok := msg.(*serverHelloMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(serverHello, msg)
+	}
+
+	if err := c.pickTLSVersion(serverHello); err != nil {
+		return err
+	}
+
+	// If we are negotiating a protocol version that's lower than what we
+	// support, check for the server downgrade canaries.
+	// See RFC 8446, Section 4.1.3.
+	maxVers := c.config.maxSupportedVersion(roleClient)
+	tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12
+	tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11
+	if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) ||
+		maxVers == VersionTLS12 && c.vers <= VersionTLS11 && tls11Downgrade {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: downgrade attempt detected, possibly due to a MitM attack or a broken middlebox")
+	}
+
+	if c.vers == VersionTLS13 {
+		hs := &clientHandshakeStateTLS13{
+			c:               c,
+			ctx:             ctx,
+			serverHello:     serverHello,
+			hello:           hello,
+			helloInner:      helloInner,
+			keySharePrivate: ecdheParams,
+			session:         session,
+			earlySecret:     earlySecret,
+			binderKey:       binderKey,
+			hsTimings:       hsTimings,
+		}
+
+		// In TLS 1.3, session tickets are delivered after the handshake.
+		return hs.handshake()
+	}
+
+	c.serverName = hello.serverName
+	hs := &clientHandshakeState{
+		c:           c,
+		ctx:         ctx,
+		serverHello: serverHello,
+		hello:       hello,
+		session:     session,
+	}
+
+	if err := hs.handshake(); err != nil {
+		return err
+	}
+
+	// If we had a successful handshake and hs.session is different from
+	// the one already cached - cache a new one.
+	if cacheKey != "" && hs.session != nil && session != hs.session {
+		c.config.ClientSessionCache.Put(cacheKey, hs.session)
+	}
+
+	return nil
+}
+
+func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
+	session *ClientSessionState, earlySecret, binderKey []byte,
+) {
+	if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil || c.config.ECHEnabled {
+		return "", nil, nil, nil
+	}
+
+	hello.ticketSupported = true
+
+	if hello.supportedVersions[0] == VersionTLS13 {
+		// Require DHE on resumption as it guarantees forward secrecy against
+		// compromise of the session ticket key. See RFC 8446, Section 4.2.9.
+		hello.pskModes = []uint8{pskModeDHE}
+	}
+
+	// Session resumption is not allowed if renegotiating because
+	// renegotiation is primarily used to allow a client to send a client
+	// certificate, which would be skipped if session resumption occurred.
+	if c.handshakes != 0 {
+		return "", nil, nil, nil
+	}
+
+	// Try to resume a previously negotiated TLS session, if available.
+	cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+	session, ok := c.config.ClientSessionCache.Get(cacheKey)
+	if !ok || session == nil {
+		return cacheKey, nil, nil, nil
+	}
+
+	// Check that version used for the previous session is still valid.
+	versOk := false
+	for _, v := range hello.supportedVersions {
+		if v == session.vers {
+			versOk = true
+			break
+		}
+	}
+	if !versOk {
+		return cacheKey, nil, nil, nil
+	}
+
+	// Check that the cached server certificate is not expired, and that it's
+	// valid for the ServerName. This should be ensured by the cache key, but
+	// protect the application from a faulty ClientSessionCache implementation.
+	if !c.config.InsecureSkipVerify {
+		if len(session.verifiedChains) == 0 {
+			// The original connection had InsecureSkipVerify, while this doesn't.
+			return cacheKey, nil, nil, nil
+		}
+		serverCert := session.serverCertificates[0]
+		if c.config.time().After(serverCert.NotAfter) {
+			// Expired certificate, delete the entry.
+			c.config.ClientSessionCache.Put(cacheKey, nil)
+			return cacheKey, nil, nil, nil
+		}
+		if err := serverCert.VerifyHostname(c.config.ServerName); err != nil {
+			return cacheKey, nil, nil, nil
+		}
+	}
+
+	if session.vers != VersionTLS13 {
+		// In TLS 1.2 the cipher suite must match the resumed session. Ensure we
+		// are still offering it.
+		if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil {
+			return cacheKey, nil, nil, nil
+		}
+
+		hello.sessionTicket = session.sessionTicket
+		return
+	}
+
+	// Check that the session ticket is not expired.
+	if c.config.time().After(session.useBy) {
+		c.config.ClientSessionCache.Put(cacheKey, nil)
+		return cacheKey, nil, nil, nil
+	}
+
+	// In TLS 1.3 the KDF hash must match the resumed session. Ensure we
+	// offer at least one cipher suite with that hash.
+	cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite)
+	if cipherSuite == nil {
+		return cacheKey, nil, nil, nil
+	}
+	cipherSuiteOk := false
+	for _, offeredID := range hello.cipherSuites {
+		offeredSuite := cipherSuiteTLS13ByID(offeredID)
+		if offeredSuite != nil && offeredSuite.hash == cipherSuite.hash {
+			cipherSuiteOk = true
+			break
+		}
+	}
+	if !cipherSuiteOk {
+		return cacheKey, nil, nil, nil
+	}
+
+	// Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
+	ticketAge := uint32(c.config.time().Sub(session.receivedAt) / time.Millisecond)
+	identity := pskIdentity{
+		label:               session.sessionTicket,
+		obfuscatedTicketAge: ticketAge + session.ageAdd,
+	}
+	hello.pskIdentities = []pskIdentity{identity}
+	hello.pskBinders = [][]byte{make([]byte, cipherSuite.hash.Size())}
+
+	// Compute the PSK binders. See RFC 8446, Section 4.2.11.2.
+	psk := cipherSuite.expandLabel(session.masterSecret, "resumption",
+		session.nonce, cipherSuite.hash.Size())
+	earlySecret = cipherSuite.extract(psk, nil)
+	binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
+	transcript := cipherSuite.hash.New()
+	transcript.Write(hello.marshalWithoutBinders())
+	pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)}
+	hello.updateBinders(pskBinders)
+
+	return
+}
+
+func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error {
+	peerVersion := serverHello.vers
+	if serverHello.supportedVersion != 0 {
+		peerVersion = serverHello.supportedVersion
+	}
+
+	vers, ok := c.config.mutualVersion(roleClient, []uint16{peerVersion})
+	if !ok {
+		c.sendAlert(alertProtocolVersion)
+		return fmt.Errorf("tls: server selected unsupported protocol version %x", peerVersion)
+	}
+
+	c.vers = vers
+	c.haveVers = true
+	c.in.version = vers
+	c.out.version = vers
+
+	return nil
+}
+
+// Does the handshake, either a full one or resumes old session. Requires hs.c,
+// hs.hello, hs.serverHello, and, optionally, hs.session to be set.
+func (hs *clientHandshakeState) handshake() error {
+	c := hs.c
+
+	isResume, err := hs.processServerHello()
+	if err != nil {
+		return err
+	}
+
+	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+
+	// No signatures of the handshake are needed in a resumption.
+	// Otherwise, in a full handshake, if we don't have any certificates
+	// configured then we will never send a CertificateVerify message and
+	// thus no signatures are needed in that case either.
+	if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) {
+		hs.finishedHash.discardHandshakeBuffer()
+	}
+
+	hs.finishedHash.Write(hs.hello.marshal())
+	hs.finishedHash.Write(hs.serverHello.marshal())
+
+	c.buffering = true
+	c.didResume = isResume
+	if isResume {
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.readSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(c.serverFinished[:]); err != nil {
+			return err
+		}
+		c.clientFinishedIsFirst = false
+		// 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
+			}
+		}
+		if err := hs.sendFinished(c.clientFinished[:]); err != nil {
+			return err
+		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+	} else {
+		if err := hs.doFullHandshake(); err != nil {
+			return err
+		}
+		if err := hs.establishKeys(); err != nil {
+			return err
+		}
+		if err := hs.sendFinished(c.clientFinished[:]); err != nil {
+			return err
+		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+		c.clientFinishedIsFirst = true
+		if err := hs.readSessionTicket(); err != nil {
+			return err
+		}
+		if err := hs.readFinished(c.serverFinished[:]); err != nil {
+			return err
+		}
+	}
+
+	c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
+	atomic.StoreUint32(&c.handshakeStatus, 1)
+
+	return nil
+}
+
+func (hs *clientHandshakeState) pickCipherSuite() error {
+	if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil {
+		hs.c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: server chose an unconfigured cipher suite")
+	}
+
+	hs.c.cipherSuite = hs.suite.id
+	return nil
+}
+
+func (hs *clientHandshakeState) doFullHandshake() error {
+	c := hs.c
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	certMsg, ok := msg.(*certificateMsg)
+	if !ok || len(certMsg.certificates) == 0 {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certMsg, msg)
+	}
+	hs.finishedHash.Write(certMsg.marshal())
+
+	msg, err = c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	cs, ok := msg.(*certificateStatusMsg)
+	if ok {
+		// RFC4366 on Certificate Status Request:
+		// The server MAY return a "certificate_status" message.
+
+		if !hs.serverHello.ocspStapling {
+			// If a server returns a "CertificateStatus" message, then the
+			// server MUST have included an extension of type "status_request"
+			// with empty "extension_data" in the extended server hello.
+
+			c.sendAlert(alertUnexpectedMessage)
+			return errors.New("tls: received unexpected CertificateStatus message")
+		}
+		hs.finishedHash.Write(cs.marshal())
+
+		c.ocspResponse = cs.response
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	if c.handshakes == 0 {
+		// If this is the first handshake on a connection, process and
+		// (optionally) verify the server's certificates.
+		if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
+			return err
+		}
+	} else {
+		// This is a renegotiation handshake. We require that the
+		// server's identity (i.e. leaf certificate) is unchanged and
+		// thus any previous trust decision is still valid.
+		//
+		// See https://mitls.org/pages/attacks/3SHAKE for the
+		// motivation behind this requirement.
+		if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: server's identity changed during renegotiation")
+		}
+	}
+
+	keyAgreement := hs.suite.ka(c.vers)
+
+	skx, ok := msg.(*serverKeyExchangeMsg)
+	if ok {
+		hs.finishedHash.Write(skx.marshal())
+		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
+		if err != nil {
+			c.sendAlert(alertUnexpectedMessage)
+			return err
+		}
+
+		if eccKex, ok := keyAgreement.(*ecdheKeyAgreement); ok {
+			c.handleCFEvent(CFEventTLSNegotiatedNamedKEX{
+				KEX: eccKex.params.CurveID(),
+			})
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	var chainToSend *Certificate
+	var certRequested bool
+	certReq, ok := msg.(*certificateRequestMsg)
+	if ok {
+		certRequested = true
+		hs.finishedHash.Write(certReq.marshal())
+
+		cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
+		if chainToSend, err = c.getClientCertificate(cri); err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+
+		msg, err = c.readHandshake()
+		if err != nil {
+			return err
+		}
+	}
+
+	shd, ok := msg.(*serverHelloDoneMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(shd, msg)
+	}
+	hs.finishedHash.Write(shd.marshal())
+
+	// If the server requested a certificate then we have to send a
+	// Certificate message, even if it's empty because we don't have a
+	// certificate to send.
+	if certRequested {
+		certMsg = new(certificateMsg)
+		certMsg.certificates = chainToSend.Certificate
+		hs.finishedHash.Write(certMsg.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+			return err
+		}
+	}
+
+	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0])
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+	if ckx != nil {
+		hs.finishedHash.Write(ckx.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil {
+			return err
+		}
+	}
+
+	if chainToSend != nil && len(chainToSend.Certificate) > 0 {
+		certVerify := &certificateVerifyMsg{}
+
+		key, ok := chainToSend.PrivateKey.(crypto.Signer)
+		if !ok {
+			c.sendAlert(alertInternalError)
+			return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
+		}
+
+		var sigType uint8
+		var sigHash crypto.Hash
+		if c.vers >= VersionTLS12 {
+			signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms)
+			if err != nil {
+				c.sendAlert(alertIllegalParameter)
+				return err
+			}
+			sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
+			if err != nil {
+				return c.sendAlert(alertInternalError)
+			}
+			certVerify.hasSignatureAlgorithm = true
+			certVerify.signatureAlgorithm = signatureAlgorithm
+		} else {
+			sigType, sigHash, err = legacyTypeAndHashFromPublicKey(key.Public())
+			if err != nil {
+				c.sendAlert(alertIllegalParameter)
+				return err
+			}
+		}
+
+		signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash, hs.masterSecret)
+		signOpts := crypto.SignerOpts(sigHash)
+		if sigType == signatureRSAPSS {
+			signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+		}
+		certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+
+		hs.finishedHash.Write(certVerify.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil {
+			return err
+		}
+	}
+
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+	if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: failed to write to key log: " + err.Error())
+	}
+
+	hs.finishedHash.discardHandshakeBuffer()
+
+	return nil
+}
+
+func (hs *clientHandshakeState) establishKeys() error {
+	c := hs.c
+
+	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+	var clientCipher, serverCipher any
+	var clientHash, serverHash hash.Hash
+	if hs.suite.cipher != nil {
+		clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
+		clientHash = hs.suite.mac(clientMAC)
+		serverCipher = hs.suite.cipher(serverKey, serverIV, true /* 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, serverCipher, serverHash)
+	c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
+	return nil
+}
+
+func (hs *clientHandshakeState) serverResumedSession() bool {
+	// If the server responded with the same sessionId then it means the
+	// sessionTicket is being used to resume a TLS session.
+	return hs.session != nil && hs.hello.sessionId != nil &&
+		bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
+}
+
+func (hs *clientHandshakeState) processServerHello() (bool, error) {
+	c := hs.c
+
+	if err := hs.pickCipherSuite(); err != nil {
+		return false, err
+	}
+
+	if hs.serverHello.compressionMethod != compressionNone {
+		c.sendAlert(alertUnexpectedMessage)
+		return false, errors.New("tls: server selected unsupported compression format")
+	}
+
+	if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported {
+		c.secureRenegotiation = true
+		if len(hs.serverHello.secureRenegotiation) != 0 {
+			c.sendAlert(alertHandshakeFailure)
+			return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+		}
+	}
+
+	if c.handshakes > 0 && c.secureRenegotiation {
+		var expectedSecureRenegotiation [24]byte
+		copy(expectedSecureRenegotiation[:], c.clientFinished[:])
+		copy(expectedSecureRenegotiation[12:], c.serverFinished[:])
+		if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) {
+			c.sendAlert(alertHandshakeFailure)
+			return false, errors.New("tls: incorrect renegotiation extension contents")
+		}
+	}
+
+	if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol); err != nil {
+		c.sendAlert(alertUnsupportedExtension)
+		return false, err
+	}
+	c.clientProtocol = hs.serverHello.alpnProtocol
+
+	c.scts = hs.serverHello.scts
+
+	if !hs.serverResumedSession() {
+		return false, nil
+	}
+
+	if hs.session.vers != c.vers {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server resumed a session with a different version")
+	}
+
+	if hs.session.cipherSuite != hs.suite.id {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server resumed a session with a different cipher suite")
+	}
+
+	// Restore masterSecret, peerCerts, and ocspResponse from previous state
+	hs.masterSecret = hs.session.masterSecret
+	c.peerCertificates = hs.session.serverCertificates
+	c.verifiedChains = hs.session.verifiedChains
+	c.ocspResponse = hs.session.ocspResponse
+	// Let the ServerHello SCTs override the session SCTs from the original
+	// connection, if any are provided
+	if len(c.scts) == 0 && len(hs.session.scts) != 0 {
+		c.scts = hs.session.scts
+	}
+
+	return true, nil
+}
+
+// checkALPN ensure that the server's choice of ALPN protocol is compatible with
+// the protocols that we advertised in the Client Hello.
+func checkALPN(clientProtos []string, serverProto string) error {
+	if serverProto == "" {
+		return nil
+	}
+	if len(clientProtos) == 0 {
+		return errors.New("tls: server advertised unrequested ALPN extension")
+	}
+	for _, proto := range clientProtos {
+		if proto == serverProto {
+			return nil
+		}
+	}
+	return errors.New("tls: server selected unadvertised ALPN protocol")
+}
+
+func (hs *clientHandshakeState) readFinished(out []byte) error {
+	c := hs.c
+
+	if err := c.readChangeCipherSpec(); err != nil {
+		return err
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	serverFinished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(serverFinished, msg)
+	}
+
+	verify := hs.finishedHash.serverSum(hs.masterSecret)
+	if len(verify) != len(serverFinished.verifyData) ||
+		subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: server's Finished message was incorrect")
+	}
+	hs.finishedHash.Write(serverFinished.marshal())
+	copy(out, verify)
+	return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+	if !hs.serverHello.ticketSupported {
+		return nil
+	}
+
+	c := hs.c
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+	sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(sessionTicketMsg, msg)
+	}
+	hs.finishedHash.Write(sessionTicketMsg.marshal())
+
+	hs.session = &ClientSessionState{
+		sessionTicket:      sessionTicketMsg.ticket,
+		vers:               c.vers,
+		cipherSuite:        hs.suite.id,
+		masterSecret:       hs.masterSecret,
+		serverCertificates: c.peerCertificates,
+		verifiedChains:     c.verifiedChains,
+		receivedAt:         c.config.time(),
+		ocspResponse:       c.ocspResponse,
+		scts:               c.scts,
+	}
+
+	return nil
+}
+
+func (hs *clientHandshakeState) sendFinished(out []byte) error {
+	c := hs.c
+
+	if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+		return err
+	}
+
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+	hs.finishedHash.Write(finished.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+		return err
+	}
+	copy(out, finished.verifyData)
+	return nil
+}
+
+// verifyServerCertificate parses and verifies the provided chain, setting
+// c.verifiedChains and c.peerCertificates or sending the appropriate alert.
+func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
+	certs := make([]*x509.Certificate, len(certificates))
+	for i, asn1Data := range certificates {
+		cert, err := x509.ParseCertificate(asn1Data)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: failed to parse certificate from server: " + err.Error())
+		}
+		certs[i] = cert
+	}
+
+	if !c.config.InsecureSkipVerify {
+		dnsName := c.config.ServerName
+		if c.ech.offered && !c.ech.accepted {
+			dnsName = c.serverName
+		}
+		opts := x509.VerifyOptions{
+			Roots:         c.config.RootCAs,
+			CurrentTime:   c.config.time(),
+			DNSName:       dnsName,
+			Intermediates: x509.NewCertPool(),
+		}
+		for _, cert := range certs[1:] {
+			opts.Intermediates.AddCert(cert)
+		}
+		var err error
+		c.verifiedChains, err = certs[0].Verify(opts)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	switch certs[0].PublicKey.(type) {
+	case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey, circlSign.PublicKey:
+		break
+	default:
+		c.sendAlert(alertUnsupportedCertificate)
+		return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
+	}
+
+	c.peerCertificates = certs
+
+	if c.config.VerifyPeerCertificate != nil {
+		if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	if c.config.VerifyConnection != nil {
+		if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	return nil
+}
+
+// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
+// <= 1.2 CertificateRequest, making an effort to fill in missing information.
+func certificateRequestInfoFromMsg(ctx context.Context, vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
+	cri := &CertificateRequestInfo{
+		AcceptableCAs: certReq.certificateAuthorities,
+		Version:       vers,
+		ctx:           ctx,
+
+		SupportsDelegatedCredential: false, // Not supported in TLS <= 1.2
+		SignatureSchemesDC:          nil,   // Not supported in TLS <= 1.2
+	}
+
+	var rsaAvail, ecAvail bool
+	for _, certType := range certReq.certificateTypes {
+		switch certType {
+		case certTypeRSASign:
+			rsaAvail = true
+		case certTypeECDSASign:
+			ecAvail = true
+		}
+	}
+
+	if !certReq.hasSignatureAlgorithm {
+		// Prior to TLS 1.2, signature schemes did not exist. In this case we
+		// make up a list based on the acceptable certificate types, to help
+		// GetClientCertificate and SupportsCertificate select the right certificate.
+		// The hash part of the SignatureScheme is a lie here, because
+		// TLS 1.0 and 1.1 always use MD5+SHA1 for RSA and SHA1 for ECDSA.
+		switch {
+		case rsaAvail && ecAvail:
+			cri.SignatureSchemes = []SignatureScheme{
+				ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
+				PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
+			}
+		case rsaAvail:
+			cri.SignatureSchemes = []SignatureScheme{
+				PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
+			}
+		case ecAvail:
+			cri.SignatureSchemes = []SignatureScheme{
+				ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
+			}
+		}
+		return cri
+	}
+
+	// Filter the signature schemes based on the certificate types.
+	// See RFC 5246, Section 7.4.4 (where it calls this "somewhat complicated").
+	cri.SignatureSchemes = make([]SignatureScheme, 0, len(certReq.supportedSignatureAlgorithms))
+	for _, sigScheme := range certReq.supportedSignatureAlgorithms {
+		sigType, _, err := typeAndHashFromSignatureScheme(sigScheme)
+		if err != nil {
+			continue
+		}
+		switch sigType {
+		case signatureECDSA, signatureEd25519:
+			if ecAvail {
+				cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
+			}
+		case signatureRSAPSS, signaturePKCS1v15:
+			if rsaAvail {
+				cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
+			}
+		}
+	}
+
+	return cri
+}
+
+func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate, error) {
+	if c.config.GetClientCertificate != nil {
+		return c.config.GetClientCertificate(cri)
+	}
+
+	for _, chain := range c.config.Certificates {
+		if err := cri.SupportsCertificate(&chain); err != nil {
+			continue
+		}
+		return &chain, nil
+	}
+
+	// No acceptable certificate found. Don't send a certificate.
+	return new(Certificate), nil
+}
+
+// clientSessionCacheKey returns a key used to cache sessionTickets that could
+// be used to resume previously negotiated TLS sessions with a server.
+func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
+	if len(config.ServerName) > 0 {
+		return config.ServerName
+	}
+	return serverAddr.String()
+}
+
+// hostnameInSNI converts name into an appropriate hostname for SNI.
+// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
+// See RFC 6066, Section 3.
+func hostnameInSNI(name string) string {
+	host := name
+	if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+		host = host[1 : len(host)-1]
+	}
+	if i := strings.LastIndex(host, "%"); i > 0 {
+		host = host[:i]
+	}
+	if net.ParseIP(host) != nil {
+		return ""
+	}
+	for len(name) > 0 && name[len(name)-1] == '.' {
+		name = name[:len(name)-1]
+	}
+	return name
+}

+ 1032 - 0
transport/cloudflaretls/handshake_client_tls13.go

@@ -0,0 +1,1032 @@
+// 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 tls
+
+import (
+	"bytes"
+	"context"
+	"crypto"
+	"crypto/hmac"
+	"crypto/rsa"
+	"crypto/subtle"
+	"errors"
+	"fmt"
+	"hash"
+	"sync/atomic"
+	"time"
+
+	circlKem "github.com/cloudflare/circl/kem"
+)
+
+type clientHandshakeStateTLS13 struct {
+	c               *Conn
+	ctx             context.Context
+	serverHello     *serverHelloMsg
+	hello           *clientHelloMsg
+	helloInner      *clientHelloMsg
+	keySharePrivate clientKeySharePrivate
+
+	session       *ClientSessionState
+	earlySecret   []byte
+	binderKey     []byte
+	selectedGroup CurveID
+
+	certReq         *certificateRequestMsgTLS13
+	usingPSK        bool
+	sentDummyCCS    bool
+	suite           *cipherSuiteTLS13
+	transcript      hash.Hash
+	transcriptInner hash.Hash
+	masterSecret    []byte
+	trafficSecret   []byte // client_application_traffic_secret_0
+
+	hsTimings CFEventTLS13ClientHandshakeTimingInfo
+}
+
+// processDelegatedCredentialFromServer unmarshals the DelegatedCredential
+// offered by the server (if present) and validates it using the peer's
+// certificate.
+func (hs *clientHandshakeStateTLS13) processDelegatedCredentialFromServer(rawDC []byte, certVerifyMsg *certificateVerifyMsg) error {
+	c := hs.c
+
+	var dc *DelegatedCredential
+	var err error
+	if rawDC != nil {
+		// Assert that support for the DC extension was indicated by the client.
+		if !hs.hello.delegatedCredentialSupported {
+			c.sendAlert(alertUnexpectedMessage)
+			return errors.New("tls: got Delegated Credential extension without indication")
+		}
+
+		dc, err = UnmarshalDelegatedCredential(rawDC)
+		if err != nil {
+			c.sendAlert(alertDecodeError)
+			return fmt.Errorf("tls: Delegated Credential: %s", err)
+		}
+
+		if !isSupportedSignatureAlgorithm(dc.cred.expCertVerfAlgo, supportedSignatureAlgorithmsDC) {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: Delegated Credential used with invalid signature algorithm")
+		}
+		if !isSupportedSignatureAlgorithm(dc.algorithm, c.config.supportedSignatureAlgorithms()) {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: Delegated Credential signed with unsupported signature algorithm")
+		}
+	}
+
+	if dc != nil {
+		if !dc.Validate(c.peerCertificates[0], false, c.config.time(), certVerifyMsg) {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: invalid Delegated Credential")
+		}
+	}
+
+	c.verifiedDC = dc
+
+	return nil
+}
+
+// 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
+
+	// 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.keySharePrivate == nil || len(hs.hello.keyShares) != 1 {
+		return c.sendAlert(alertInternalError)
+	}
+
+	if err := hs.checkServerHelloOrHRR(); err != nil {
+		return err
+	}
+
+	hs.transcript = hs.suite.hash.New()
+	hs.transcript.Write(hs.hello.marshal())
+
+	// When offering ECH, we don't know whether ECH was accepted or rejected
+	// until we get the server's response. Compute the transcript of both the
+	// inner and outer handshake until we know.
+	if c.ech.offered {
+		hs.transcriptInner = hs.suite.hash.New()
+		hs.transcriptInner.Write(hs.helloInner.marshal())
+	}
+
+	if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
+		if err := hs.sendDummyChangeCipherSpec(); err != nil {
+			return err
+		}
+		if err := hs.processHelloRetryRequest(); err != nil {
+			return err
+		}
+	}
+
+	// Check for ECH acceptance confirmation.
+	if c.ech.offered {
+		echAcceptConfTranscript := cloneHash(hs.transcriptInner, hs.suite.hash)
+		if echAcceptConfTranscript == nil {
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: internal error: failed to clone hash")
+		}
+
+		sh := hs.serverHello.marshal()
+		echAcceptConfTranscript.Write(sh[:30])
+		echAcceptConfTranscript.Write(zeros[:8])
+		echAcceptConfTranscript.Write(sh[38:])
+		echAcceptConf := hs.suite.expandLabel(
+			hs.suite.extract(hs.helloInner.random, nil),
+			echAcceptConfLabel,
+			echAcceptConfTranscript.Sum(nil),
+			8)
+
+		if subtle.ConstantTimeCompare(hs.serverHello.random[24:], echAcceptConf) == 1 {
+			c.ech.accepted = true
+			hs.hello = hs.helloInner
+			hs.transcript = hs.transcriptInner
+		}
+	}
+
+	hs.transcript.Write(hs.serverHello.marshal())
+
+	// Resolve the server name now that ECH acceptance has been determined.
+	//
+	// NOTE(cjpatton): Currently the client sends the same ALPN extension in the
+	// ClientHelloInner and ClientHelloOuter. If that changes, then we'll need
+	// to resolve ALPN here as well.
+	c.serverName = hs.hello.serverName
+
+	c.buffering = true
+	if err := hs.processServerHello(); err != nil {
+		return err
+	}
+	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
+	}
+	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 := hs.abortIfRequired(); err != nil {
+		return err
+	}
+	if _, err := c.flush(); err != nil {
+		return err
+	}
+
+	c.handleCFEvent(hs.hsTimings)
+	atomic.StoreUint32(&c.handshakeStatus, 1)
+
+	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
+
+	_, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	return err
+}
+
+// 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
+
+	c.handleCFEvent(CFEventTLS13HRR{})
+
+	// 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)
+	hs.transcript.Write(hs.serverHello.marshal())
+
+	// Determine which ClientHello message was consumed by the server. If ECH
+	// was offered, this may be the ClientHelloInner or ClientHelloOuter.
+	hello := hs.hello
+	isInner := false
+	if c.ech.offered {
+		chHash = hs.transcriptInner.Sum(nil)
+		hs.transcriptInner.Reset()
+		hs.transcriptInner.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+		hs.transcriptInner.Write(chHash)
+
+		// Check for ECH acceptance confirmation.
+		if hs.serverHello.ech != nil {
+			if len(hs.serverHello.ech) != 8 {
+				c.sendAlert(alertDecodeError)
+				return errors.New("tls: ech: hrr: malformed acceptance signal")
+			}
+
+			echAcceptConfHRRTranscript := cloneHash(hs.transcriptInner, hs.suite.hash)
+			if echAcceptConfHRRTranscript == nil {
+				c.sendAlert(alertInternalError)
+				return errors.New("tls: internal error: failed to clone hash")
+			}
+
+			echAcceptConfHRR := echEncodeAcceptConfHelloRetryRequest(hs.serverHello.marshal())
+			echAcceptConfHRRTranscript.Write(echAcceptConfHRR)
+			echAcceptConfHRRSignal := hs.suite.expandLabel(
+				hs.suite.extract(hs.helloInner.random, nil),
+				echAcceptConfHRRLabel,
+				echAcceptConfHRRTranscript.Sum(nil),
+				8)
+
+			if subtle.ConstantTimeCompare(hs.serverHello.ech, echAcceptConfHRRSignal) == 1 {
+				hello = hs.helloInner
+				isInner = true
+			}
+		}
+
+		hs.transcriptInner.Write(hs.serverHello.marshal())
+	}
+
+	// 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 {
+		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 hello.supportedCurves {
+			if id == curveID {
+				curveOK = true
+				break
+			}
+		}
+		if !curveOK {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: server selected unsupported group")
+		}
+		if clientKeySharePrivateCurveID(hs.keySharePrivate) == curveID {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
+		}
+		if scheme := curveIdToCirclScheme(curveID); scheme != nil {
+			pk, sk, err := generateKemKeyPair(scheme, c.config.rand())
+			if err != nil {
+				c.sendAlert(alertInternalError)
+				return fmt.Errorf("HRR generateKemKeyPair %s: %w",
+					scheme.Name(), err)
+			}
+			packedPk, err := pk.MarshalBinary()
+			if err != nil {
+				c.sendAlert(alertInternalError)
+				return fmt.Errorf("HRR pack circl public key %s: %w",
+					scheme.Name(), err)
+			}
+			hs.keySharePrivate = sk
+			hello.keyShares = []keyShare{{group: curveID, data: packedPk}}
+		} else {
+			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.keySharePrivate = params
+			hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
+		}
+	}
+
+	hello.raw = nil
+	if len(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)
+			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)
+			transcript.Write(hs.serverHello.marshal())
+			transcript.Write(hello.marshalWithoutBinders())
+			pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)}
+			hello.updateBinders(pskBinders)
+		} else {
+			// Server selected a cipher suite incompatible with the PSK.
+			hello.pskIdentities = nil
+			hello.pskBinders = nil
+		}
+	}
+
+	if isInner {
+		hs.helloInner = hello
+		hs.transcriptInner.Write(hs.helloInner.marshal())
+		if err := c.echUpdateClientHelloOuter(hs.hello, hs.helloInner, nil); err != nil {
+			return err
+		}
+	} else {
+		hs.hello = hello
+	}
+
+	if c.ech.offered && testingECHIllegalHandleAfterHRR {
+		hs.hello.raw = nil
+
+		// Change the cipher suite and config id and set an encapsulated key in
+		// the updated ClientHello. This will trigger a server abort because the
+		// cipher suite and config id are supposed to match the previous
+		// ClientHello and the encapsulated key is supposed to be empty.
+		var ech echClientOuter
+		_, kdf, aead := c.ech.sealer.Suite().Params()
+		ech.handle.suite.kdfId = uint16(kdf) ^ 0xff
+		ech.handle.suite.aeadId = uint16(aead) ^ 0xff
+		ech.handle.configId = c.ech.configId ^ 0xff
+		ech.handle.enc = []byte{1, 2, 3, 4, 5}
+		ech.payload = []byte{1, 2, 3, 4, 5}
+		hs.hello.ech = ech.marshal()
+	}
+
+	if testingECHTriggerBypassAfterHRR {
+		hs.hello.raw = nil
+
+		// Don't send the ECH extension in the updated ClientHello. This will
+		// trigger a server abort, since this is illegal.
+		hs.hello.ech = nil
+	}
+
+	if testingECHTriggerBypassBeforeHRR {
+		hs.hello.raw = nil
+
+		// Send a dummy ECH extension in the updated ClientHello. This will
+		// trigger a server abort, since no ECH extension was sent in the
+		// previous ClientHello.
+		var err error
+		hs.hello.ech, err = echGenerateGreaseExt(c.config.rand())
+		if err != nil {
+			return fmt.Errorf("tls: ech: failed to generate grease ECH: %s", err)
+		}
+	}
+
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+		return err
+	}
+
+	msg, err := c.readHandshake()
+	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
+	}
+
+	hs.transcript.Write(hs.hello.marshal())
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) processServerHello() error {
+	c := hs.c
+
+	defer func() {
+		hs.hsTimings.ProcessServerHello = hs.hsTimings.elapsedTime()
+	}()
+
+	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 != clientKeySharePrivateCurveID(hs.keySharePrivate) {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: server selected unsupported group")
+	}
+
+	c.handleCFEvent(CFEventTLSNegotiatedNamedKEX{
+		KEX: hs.serverHello.serverShare.group,
+	})
+
+	if !hs.serverHello.selectedIdentityPresent {
+		return nil
+	}
+
+	// Per the rules of draft-ietf-tls-esni-13, Section 6.1, the server is not
+	// permitted to resume a connection connection in the outer handshake. If
+	// ECH is rejected and the client-facing server replies with a
+	// "pre_shared_key" extension in its ServerHello, then the client MUST abort
+	// the handshake with an "illegal_parameter" alert.
+	if c.ech.offered && !c.ech.accepted {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: ech: client-facing server offered PSK after ECH rejection")
+	}
+
+	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
+
+	var sharedKey []byte
+	if params, ok := hs.keySharePrivate.(ecdheParameters); ok {
+		sharedKey = params.SharedKey(hs.serverHello.serverShare.data)
+	} else if sk, ok := hs.keySharePrivate.(circlKem.PrivateKey); ok {
+		var err error
+		sharedKey, err = sk.Scheme().Decapsulate(sk, hs.serverHello.serverShare.data)
+		if err != nil {
+			c.sendAlert(alertIllegalParameter)
+			return fmt.Errorf("%s decaps: %w", sk.Scheme().Name(), err)
+		}
+	}
+
+	if sharedKey == nil {
+		c.sendAlert(alertIllegalParameter)
+		return fmt.Errorf("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.setTrafficSecret(hs.suite, clientSecret)
+	serverSecret := hs.suite.deriveSecret(handshakeSecret,
+		serverHandshakeTrafficLabel, hs.transcript)
+	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()
+	if err != nil {
+		return err
+	}
+
+	encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(encryptedExtensions, msg)
+	}
+	hs.transcript.Write(encryptedExtensions.marshal())
+
+	if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil {
+		c.sendAlert(alertUnsupportedExtension)
+		return err
+	}
+	c.clientProtocol = encryptedExtensions.alpnProtocol
+
+	if c.ech.offered && len(encryptedExtensions.ech) > 0 {
+		if !c.ech.accepted {
+			// If the server rejects ECH, then it may send retry configurations.
+			// If present, we must check them for syntactic correctness and
+			// abort if they are not correct.
+			c.ech.retryConfigs = encryptedExtensions.ech
+			if _, err = UnmarshalECHConfigs(c.ech.retryConfigs); err != nil {
+				c.sendAlert(alertDecodeError)
+				return fmt.Errorf("tls: ech: failed to parse retry configs: %s", err)
+			}
+		} else {
+			// Retry configs must not be sent in the inner handshake.
+			c.sendAlert(alertUnsupportedExtension)
+			return errors.New("tls: ech: got retry configs after ECH acceptance")
+		}
+	}
+
+	hs.hsTimings.ReadEncryptedExtensions = hs.hsTimings.elapsedTime()
+
+	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()
+	if err != nil {
+		return err
+	}
+
+	certReq, ok := msg.(*certificateRequestMsgTLS13)
+	if ok {
+		hs.transcript.Write(certReq.marshal())
+
+		hs.certReq = certReq
+
+		msg, err = c.readHandshake()
+		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")
+	}
+	hs.transcript.Write(certMsg.marshal())
+
+	hs.hsTimings.ReadCertificate = hs.hsTimings.elapsedTime()
+
+	c.scts = certMsg.certificate.SignedCertificateTimestamps
+	c.ocspResponse = certMsg.certificate.OCSPStaple
+
+	if err := c.verifyServerCertificate(certMsg.certificate.Certificate); err != nil {
+		return err
+	}
+
+	msg, err = c.readHandshake()
+	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, c.config.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")
+	}
+	if certMsg.delegatedCredential {
+		if err := hs.processDelegatedCredentialFromServer(certMsg.certificate.DelegatedCredential, certVerify); err != nil {
+			return err // alert sent
+		}
+	}
+
+	pk := c.peerCertificates[0].PublicKey
+	if c.verifiedDC != nil {
+		pk = c.verifiedDC.cred.publicKey
+	}
+
+	signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
+	if err := verifyHandshakeSignature(sigType, pk,
+		sigHash, signed, certVerify.signature); err != nil {
+		c.sendAlert(alertDecryptError)
+		return errors.New("tls: invalid signature by the server certificate: " + err.Error())
+	}
+
+	hs.transcript.Write(certVerify.marshal())
+
+	hs.hsTimings.ReadCertificateVerify = hs.hsTimings.elapsedTime()
+
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerFinished() error {
+	c := hs.c
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	finished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(finished, msg)
+	}
+
+	hs.hsTimings.ReadServerFinished = hs.hsTimings.elapsedTime()
+
+	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")
+	}
+
+	hs.transcript.Write(finished.marshal())
+
+	// 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.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 certificateRequestInfo(certReq *certificateRequestMsgTLS13, vers uint16, ctx context.Context) *CertificateRequestInfo {
+	cri := &CertificateRequestInfo{
+		SupportsDelegatedCredential: certReq.supportDelegatedCredential,
+		SignatureSchemes:            certReq.supportedSignatureAlgorithms,
+		SignatureSchemesDC:          certReq.supportedSignatureAlgorithmsDC,
+		AcceptableCAs:               certReq.certificateAuthorities,
+		Version:                     vers,
+		ctx:                         ctx,
+	}
+
+	return cri
+}
+
+// getClientDelegatedCredential will return a Delegated Credential pair (a
+// Delegated Credential and its private key) for the given CertificateRequestInfo,
+// defaulting to the first element of cert.DelegatedCredentialPair.
+// The returned Delegated Credential could be invalid for usage in the handshake.
+// Returns an error if there are no delegated credentials or if the one found
+// cannot be used for the current connection.
+func getClientDelegatedCredential(cri *CertificateRequestInfo, cert *Certificate) (*DelegatedCredentialPair, error) {
+	if len(cert.DelegatedCredentials) == 0 {
+		return nil, errors.New("no Delegated Credential found")
+	}
+
+	for _, dcPair := range cert.DelegatedCredentials {
+		// If the client sent the signature_algorithms in the DC extension, ensure it supports
+		// schemes we can use with this delegated credential.
+		if len(cri.SignatureSchemesDC) > 0 {
+			if _, err := selectSignatureSchemeDC(VersionTLS13, dcPair.DC, cri.SignatureSchemes, cri.SignatureSchemesDC); err == nil {
+				return &dcPair, nil
+			}
+		}
+	}
+
+	// No delegated credential can be returned.
+	return nil, errors.New("no valid Delegated Credential found")
+}
+
+func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
+	c := hs.c
+
+	if hs.certReq == nil {
+		return nil
+	}
+
+	cri := certificateRequestInfo(hs.certReq, c.vers, hs.ctx)
+
+	cert, err := c.getClientCertificate(cri)
+	if err != nil {
+		return err
+	}
+
+	var dcPair *DelegatedCredentialPair
+	if hs.certReq.supportDelegatedCredential && len(hs.certReq.supportedSignatureAlgorithmsDC) > 0 {
+		// getClientDelegatedCredential selects a delegated credential that the server has advertised support for, if possible.
+		if delegatedCredentialPair, err := getClientDelegatedCredential(cri, cert); err == nil {
+			if delegatedCredentialPair.DC != nil && delegatedCredentialPair.PrivateKey != nil {
+				var err error
+				// Even if the Delegated Credential has already been marshalled, be sure it is the correct one.
+				if delegatedCredentialPair.DC.raw, err = delegatedCredentialPair.DC.Marshal(); err == nil {
+					dcPair = delegatedCredentialPair
+					cert.DelegatedCredential = dcPair.DC.raw
+				}
+			}
+		}
+	}
+
+	certMsg := new(certificateMsgTLS13)
+
+	certMsg.certificate = *cert
+	certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0
+	certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0
+	certMsg.delegatedCredential = hs.certReq.supportDelegatedCredential && len(cert.DelegatedCredential) > 0
+
+	hs.transcript.Write(certMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+		return err
+	}
+
+	hs.hsTimings.WriteCertificate = hs.hsTimings.elapsedTime()
+
+	// If we sent an empty certificate message, skip the CertificateVerify.
+	if len(cert.Certificate) == 0 {
+		return nil
+	}
+
+	certVerifyMsg := new(certificateVerifyMsg)
+	certVerifyMsg.hasSignatureAlgorithm = true
+
+	var sigAlgorithm SignatureScheme
+	suppSigAlgo := hs.certReq.supportedSignatureAlgorithms
+	sigAlgorithm, err = selectSignatureScheme(c.vers, cert, suppSigAlgo)
+	if err != nil {
+		// getClientCertificate returned a certificate incompatible with the
+		// CertificateRequestInfo supported signature algorithms.
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+
+	if certMsg.delegatedCredential {
+		suppSigAlgo = hs.certReq.supportedSignatureAlgorithmsDC
+		if dcPair == nil || dcPair.DC == nil {
+			cert.DelegatedCredential = nil
+		} else {
+			sigAlgorithm = dcPair.DC.cred.expCertVerfAlgo
+			cert.PrivateKey = dcPair.PrivateKey
+		}
+	}
+
+	certVerifyMsg.signatureAlgorithm = sigAlgorithm
+
+	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
+
+	hs.transcript.Write(certVerifyMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil {
+		return err
+	}
+
+	hs.hsTimings.WriteCertificateVerify = hs.hsTimings.elapsedTime()
+
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
+	c := hs.c
+
+	finished := &finishedMsg{
+		verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
+	}
+
+	hs.transcript.Write(finished.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+		return err
+	}
+
+	hs.hsTimings.WriteClientFinished = hs.hsTimings.elapsedTime()
+
+	c.out.setTrafficSecret(hs.suite, hs.trafficSecret)
+
+	if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil && !c.config.ECHEnabled {
+		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 || c.config.ECHEnabled {
+		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)
+	}
+
+	// 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:              msg.nonce,
+		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, session)
+
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) abortIfRequired() error {
+	c := hs.c
+	if c.ech.offered && !c.ech.accepted {
+		// If ECH was rejected, then abort the handshake.
+		c.sendAlert(alertECHRequired)
+		return errors.New("tls: ech: rejected")
+	}
+	return nil
+}

+ 1927 - 0
transport/cloudflaretls/handshake_messages.go

@@ -0,0 +1,1927 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"fmt"
+	"strings"
+
+	"golang.org/x/crypto/cryptobyte"
+)
+
+// The marshalingFunction type is an adapter to allow the use of ordinary
+// functions as cryptobyte.MarshalingValue.
+type marshalingFunction func(b *cryptobyte.Builder) error
+
+func (f marshalingFunction) Marshal(b *cryptobyte.Builder) error {
+	return f(b)
+}
+
+// addBytesWithLength appends a sequence of bytes to the cryptobyte.Builder. If
+// the length of the sequence is not the value specified, it produces an error.
+func addBytesWithLength(b *cryptobyte.Builder, v []byte, n int) {
+	b.AddValue(marshalingFunction(func(b *cryptobyte.Builder) error {
+		if len(v) != n {
+			return fmt.Errorf("invalid value length: expected %d, got %d", n, len(v))
+		}
+		b.AddBytes(v)
+		return nil
+	}))
+}
+
+// addUint64 appends a big-endian, 64-bit value to the cryptobyte.Builder.
+func addUint64(b *cryptobyte.Builder, v uint64) {
+	b.AddUint32(uint32(v >> 32))
+	b.AddUint32(uint32(v))
+}
+
+// readUint64 decodes a big-endian, 64-bit value into out and advances over it.
+// It reports whether the read was successful.
+func readUint64(s *cryptobyte.String, out *uint64) bool {
+	var hi, lo uint32
+	if !s.ReadUint32(&hi) || !s.ReadUint32(&lo) {
+		return false
+	}
+	*out = uint64(hi)<<32 | uint64(lo)
+	return true
+}
+
+// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a
+// []byte instead of a cryptobyte.String.
+func readUint8LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
+	return s.ReadUint8LengthPrefixed((*cryptobyte.String)(out))
+}
+
+// readUint16LengthPrefixed acts like s.ReadUint16LengthPrefixed, but targets a
+// []byte instead of a cryptobyte.String.
+func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
+	return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out))
+}
+
+// readUint24LengthPrefixed acts like s.ReadUint24LengthPrefixed, but targets a
+// []byte instead of a cryptobyte.String.
+func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
+	return s.ReadUint24LengthPrefixed((*cryptobyte.String)(out))
+}
+
+type clientHelloMsg struct {
+	raw                              []byte
+	vers                             uint16
+	random                           []byte
+	sessionId                        []byte
+	cipherSuites                     []uint16
+	compressionMethods               []uint8
+	serverName                       string
+	ocspStapling                     bool
+	supportedCurves                  []CurveID
+	supportedPoints                  []uint8
+	ticketSupported                  bool
+	sessionTicket                    []uint8
+	supportedSignatureAlgorithms     []SignatureScheme
+	supportedSignatureAlgorithmsCert []SignatureScheme
+	supportedSignatureAlgorithmsDC   []SignatureScheme
+	secureRenegotiationSupported     bool
+	secureRenegotiation              []byte
+	delegatedCredentialSupported     bool
+	alpnProtocols                    []string
+	scts                             bool
+	supportedVersions                []uint16
+	cookie                           []byte
+	keyShares                        []keyShare
+	earlyData                        bool
+	pskModes                         []uint8
+	pskIdentities                    []pskIdentity
+	pskBinders                       [][]byte
+	ech                              []byte
+}
+
+func (m *clientHelloMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeClientHello)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint16(m.vers)
+		addBytesWithLength(b, m.random, 32)
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(m.sessionId)
+		})
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			for _, suite := range m.cipherSuites {
+				b.AddUint16(suite)
+			}
+		})
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(m.compressionMethods)
+		})
+
+		// If extensions aren't present, omit them.
+		var extensionsPresent bool
+		bWithoutExtensions := *b
+
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			if len(m.ech) > 0 {
+				// draft-ietf-tls-esni-13, "encrypted_client_hello"
+				b.AddUint16(extensionECH)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddBytes(m.ech)
+				})
+			}
+			if len(m.serverName) > 0 {
+				// RFC 6066, Section 3
+				b.AddUint16(extensionServerName)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddUint8(0) // name_type = host_name
+						b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+							b.AddBytes([]byte(m.serverName))
+						})
+					})
+				})
+			}
+			if m.ocspStapling {
+				// RFC 4366, Section 3.6
+				b.AddUint16(extensionStatusRequest)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint8(1)  // status_type = ocsp
+					b.AddUint16(0) // empty responder_id_list
+					b.AddUint16(0) // empty request_extensions
+				})
+			}
+			if len(m.supportedCurves) > 0 {
+				// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
+				b.AddUint16(extensionSupportedCurves)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, curve := range m.supportedCurves {
+							b.AddUint16(uint16(curve))
+						}
+					})
+				})
+			}
+			if len(m.supportedPoints) > 0 {
+				// RFC 4492, Section 5.1.2
+				b.AddUint16(extensionSupportedPoints)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(m.supportedPoints)
+					})
+				})
+			}
+			if m.ticketSupported {
+				// RFC 5077, Section 3.2
+				b.AddUint16(extensionSessionTicket)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddBytes(m.sessionTicket)
+				})
+			}
+			if len(m.supportedSignatureAlgorithms) > 0 {
+				// RFC 5246, Section 7.4.1.4.1
+				b.AddUint16(extensionSignatureAlgorithms)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, sigAlgo := range m.supportedSignatureAlgorithms {
+							b.AddUint16(uint16(sigAlgo))
+						}
+					})
+				})
+			}
+			if len(m.supportedSignatureAlgorithmsCert) > 0 {
+				// RFC 8446, Section 4.2.3
+				b.AddUint16(extensionSignatureAlgorithmsCert)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
+							b.AddUint16(uint16(sigAlgo))
+						}
+					})
+				})
+			}
+			if m.secureRenegotiationSupported {
+				// RFC 5746, Section 3.2
+				b.AddUint16(extensionRenegotiationInfo)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(m.secureRenegotiation)
+					})
+				})
+			}
+			if m.delegatedCredentialSupported {
+				if len(m.supportedSignatureAlgorithmsDC) > 0 {
+					// Draft: https://tools.ietf.org/html/draft-ietf-tls-subcerts-10
+					b.AddUint16(extensionDelegatedCredentials)
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+							for _, sigAlgo := range m.supportedSignatureAlgorithmsDC {
+								b.AddUint16(uint16(sigAlgo))
+							}
+						})
+					})
+				}
+			}
+			if len(m.alpnProtocols) > 0 {
+				// RFC 7301, Section 3.1
+				b.AddUint16(extensionALPN)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, proto := range m.alpnProtocols {
+							b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+								b.AddBytes([]byte(proto))
+							})
+						}
+					})
+				})
+			}
+			if m.scts {
+				// RFC 6962, Section 3.3.1
+				b.AddUint16(extensionSCT)
+				b.AddUint16(0) // empty extension_data
+			}
+			if len(m.supportedVersions) > 0 {
+				// RFC 8446, Section 4.2.1
+				b.AddUint16(extensionSupportedVersions)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, vers := range m.supportedVersions {
+							b.AddUint16(vers)
+						}
+					})
+				})
+			}
+			if len(m.cookie) > 0 {
+				// RFC 8446, Section 4.2.2
+				b.AddUint16(extensionCookie)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(m.cookie)
+					})
+				})
+			}
+			if len(m.keyShares) > 0 {
+				// RFC 8446, Section 4.2.8
+				b.AddUint16(extensionKeyShare)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, ks := range m.keyShares {
+							b.AddUint16(uint16(ks.group))
+							b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+								b.AddBytes(ks.data)
+							})
+						}
+					})
+				})
+			}
+			if m.earlyData {
+				// RFC 8446, Section 4.2.10
+				b.AddUint16(extensionEarlyData)
+				b.AddUint16(0) // empty extension_data
+			}
+			if len(m.pskModes) > 0 {
+				// RFC 8446, Section 4.2.9
+				b.AddUint16(extensionPSKModes)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(m.pskModes)
+					})
+				})
+			}
+			if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
+				// RFC 8446, Section 4.2.11
+				b.AddUint16(extensionPreSharedKey)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, psk := range m.pskIdentities {
+							b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+								b.AddBytes(psk.label)
+							})
+							b.AddUint32(psk.obfuscatedTicketAge)
+						}
+					})
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, binder := range m.pskBinders {
+							b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+								b.AddBytes(binder)
+							})
+						}
+					})
+				})
+			}
+
+			extensionsPresent = len(b.BytesOrPanic()) > 2
+		})
+
+		if !extensionsPresent {
+			*b = bWithoutExtensions
+		}
+	})
+
+	m.raw = b.BytesOrPanic()
+	return m.raw
+}
+
+// marshalWithoutBinders returns the ClientHello through the
+// PreSharedKeyExtension.identities field, according to RFC 8446, Section
+// 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length.
+func (m *clientHelloMsg) marshalWithoutBinders() []byte {
+	bindersLen := 2 // uint16 length prefix
+	for _, binder := range m.pskBinders {
+		bindersLen += 1 // uint8 length prefix
+		bindersLen += len(binder)
+	}
+
+	fullMessage := m.marshal()
+	return fullMessage[:len(fullMessage)-bindersLen]
+}
+
+// updateBinders updates the m.pskBinders field, if necessary updating the
+// cached marshaled representation. The supplied binders must have the same
+// length as the current m.pskBinders.
+func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) {
+	if len(pskBinders) != len(m.pskBinders) {
+		panic("tls: internal error: pskBinders length mismatch")
+	}
+	for i := range m.pskBinders {
+		if len(pskBinders[i]) != len(m.pskBinders[i]) {
+			panic("tls: internal error: pskBinders length mismatch")
+		}
+	}
+	m.pskBinders = pskBinders
+	if m.raw != nil {
+		lenWithoutBinders := len(m.marshalWithoutBinders())
+		b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders])
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			for _, binder := range m.pskBinders {
+				b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddBytes(binder)
+				})
+			}
+		})
+		if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) {
+			panic("tls: internal error: failed to update binders")
+		}
+	}
+}
+
+func (m *clientHelloMsg) unmarshal(data []byte) bool {
+	*m = clientHelloMsg{raw: data}
+	s := cryptobyte.String(data)
+
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) ||
+		!readUint8LengthPrefixed(&s, &m.sessionId) {
+		return false
+	}
+
+	var cipherSuites cryptobyte.String
+	if !s.ReadUint16LengthPrefixed(&cipherSuites) {
+		return false
+	}
+	m.cipherSuites = []uint16{}
+	m.secureRenegotiationSupported = false
+	for !cipherSuites.Empty() {
+		var suite uint16
+		if !cipherSuites.ReadUint16(&suite) {
+			return false
+		}
+		if suite == scsvRenegotiation {
+			m.secureRenegotiationSupported = true
+		}
+		m.cipherSuites = append(m.cipherSuites, suite)
+	}
+
+	if !readUint8LengthPrefixed(&s, &m.compressionMethods) {
+		return false
+	}
+
+	if s.Empty() {
+		// ClientHello is optionally followed by extension data
+		return true
+	}
+
+	var extensions cryptobyte.String
+	if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+		return false
+	}
+
+	for !extensions.Empty() {
+		var extension uint16
+		var extData cryptobyte.String
+		if !extensions.ReadUint16(&extension) ||
+			!extensions.ReadUint16LengthPrefixed(&extData) {
+			return false
+		}
+
+		switch extension {
+		case extensionECH:
+			// draft-ietf-tls-esni-13, "encrypted_client_hello"
+			if len(extData) == 0 ||
+				!extData.ReadBytes(&m.ech, len(extData)) {
+				return false
+			}
+		case extensionServerName:
+			// RFC 6066, Section 3
+			var nameList cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
+				return false
+			}
+			for !nameList.Empty() {
+				var nameType uint8
+				var serverName cryptobyte.String
+				if !nameList.ReadUint8(&nameType) ||
+					!nameList.ReadUint16LengthPrefixed(&serverName) ||
+					serverName.Empty() {
+					return false
+				}
+				if nameType != 0 {
+					continue
+				}
+				if len(m.serverName) != 0 {
+					// Multiple names of the same name_type are prohibited.
+					return false
+				}
+				m.serverName = string(serverName)
+				// An SNI value may not include a trailing dot.
+				if strings.HasSuffix(m.serverName, ".") {
+					return false
+				}
+			}
+		case extensionStatusRequest:
+			// RFC 4366, Section 3.6
+			var statusType uint8
+			var ignored cryptobyte.String
+			if !extData.ReadUint8(&statusType) ||
+				!extData.ReadUint16LengthPrefixed(&ignored) ||
+				!extData.ReadUint16LengthPrefixed(&ignored) {
+				return false
+			}
+			m.ocspStapling = statusType == statusTypeOCSP
+		case extensionSupportedCurves:
+			// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
+			var curves cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&curves) || curves.Empty() {
+				return false
+			}
+			for !curves.Empty() {
+				var curve uint16
+				if !curves.ReadUint16(&curve) {
+					return false
+				}
+				m.supportedCurves = append(m.supportedCurves, CurveID(curve))
+			}
+		case extensionSupportedPoints:
+			// RFC 4492, Section 5.1.2
+			if !readUint8LengthPrefixed(&extData, &m.supportedPoints) ||
+				len(m.supportedPoints) == 0 {
+				return false
+			}
+		case extensionSessionTicket:
+			// RFC 5077, Section 3.2
+			m.ticketSupported = true
+			extData.ReadBytes(&m.sessionTicket, len(extData))
+		case extensionSignatureAlgorithms:
+			// RFC 5246, Section 7.4.1.4.1
+			var sigAndAlgs cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+				return false
+			}
+			for !sigAndAlgs.Empty() {
+				var sigAndAlg uint16
+				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+					return false
+				}
+				m.supportedSignatureAlgorithms = append(
+					m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
+			}
+		case extensionSignatureAlgorithmsCert:
+			// RFC 8446, Section 4.2.3
+			var sigAndAlgs cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+				return false
+			}
+			for !sigAndAlgs.Empty() {
+				var sigAndAlg uint16
+				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+					return false
+				}
+				m.supportedSignatureAlgorithmsCert = append(
+					m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg))
+			}
+		case extensionRenegotiationInfo:
+			// RFC 5746, Section 3.2
+			if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) {
+				return false
+			}
+			m.secureRenegotiationSupported = true
+		case extensionALPN:
+			// RFC 7301, Section 3.1
+			var protoList cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+				return false
+			}
+			for !protoList.Empty() {
+				var proto cryptobyte.String
+				if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
+					return false
+				}
+				m.alpnProtocols = append(m.alpnProtocols, string(proto))
+			}
+		case extensionSCT:
+			// RFC 6962, Section 3.3.1
+			m.scts = true
+		case extensionSupportedVersions:
+			// RFC 8446, Section 4.2.1
+			var versList cryptobyte.String
+			if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() {
+				return false
+			}
+			for !versList.Empty() {
+				var vers uint16
+				if !versList.ReadUint16(&vers) {
+					return false
+				}
+				m.supportedVersions = append(m.supportedVersions, vers)
+			}
+		case extensionCookie:
+			// RFC 8446, Section 4.2.2
+			if !readUint16LengthPrefixed(&extData, &m.cookie) ||
+				len(m.cookie) == 0 {
+				return false
+			}
+		case extensionDelegatedCredentials:
+			var sigAndAlgs cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+				return false
+			}
+			for !sigAndAlgs.Empty() {
+				var sigAndAlg uint16
+				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+					return false
+				}
+				m.supportedSignatureAlgorithmsDC = append(
+					m.supportedSignatureAlgorithmsDC, SignatureScheme(sigAndAlg))
+			}
+			m.delegatedCredentialSupported = true
+		case extensionKeyShare:
+			// RFC 8446, Section 4.2.8
+			var clientShares cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&clientShares) {
+				return false
+			}
+			for !clientShares.Empty() {
+				var ks keyShare
+				if !clientShares.ReadUint16((*uint16)(&ks.group)) ||
+					!readUint16LengthPrefixed(&clientShares, &ks.data) ||
+					len(ks.data) == 0 {
+					return false
+				}
+				m.keyShares = append(m.keyShares, ks)
+			}
+		case extensionEarlyData:
+			// RFC 8446, Section 4.2.10
+			m.earlyData = true
+		case extensionPSKModes:
+			// RFC 8446, Section 4.2.9
+			if !readUint8LengthPrefixed(&extData, &m.pskModes) {
+				return false
+			}
+		case extensionPreSharedKey:
+			// RFC 8446, Section 4.2.11
+			if !extensions.Empty() {
+				return false // pre_shared_key must be the last extension
+			}
+			var identities cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&identities) || identities.Empty() {
+				return false
+			}
+			for !identities.Empty() {
+				var psk pskIdentity
+				if !readUint16LengthPrefixed(&identities, &psk.label) ||
+					!identities.ReadUint32(&psk.obfuscatedTicketAge) ||
+					len(psk.label) == 0 {
+					return false
+				}
+				m.pskIdentities = append(m.pskIdentities, psk)
+			}
+			var binders cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&binders) || binders.Empty() {
+				return false
+			}
+			for !binders.Empty() {
+				var binder []byte
+				if !readUint8LengthPrefixed(&binders, &binder) ||
+					len(binder) == 0 {
+					return false
+				}
+				m.pskBinders = append(m.pskBinders, binder)
+			}
+		default:
+			// Ignore unknown extensions.
+			continue
+		}
+
+		if !extData.Empty() {
+			return false
+		}
+	}
+
+	return true
+}
+
+type serverHelloMsg struct {
+	raw                          []byte
+	vers                         uint16
+	random                       []byte
+	sessionId                    []byte
+	cipherSuite                  uint16
+	compressionMethod            uint8
+	ocspStapling                 bool
+	ticketSupported              bool
+	secureRenegotiationSupported bool
+	secureRenegotiation          []byte
+	alpnProtocol                 string
+	scts                         [][]byte
+	supportedVersion             uint16
+	serverShare                  keyShare
+	selectedIdentityPresent      bool
+	selectedIdentity             uint16
+	supportedPoints              []uint8
+
+	// HelloRetryRequest extensions
+	cookie        []byte
+	selectedGroup CurveID
+	ech           []byte
+}
+
+func (m *serverHelloMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeServerHello)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint16(m.vers)
+		addBytesWithLength(b, m.random, 32)
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(m.sessionId)
+		})
+		b.AddUint16(m.cipherSuite)
+		b.AddUint8(m.compressionMethod)
+
+		// If extensions aren't present, omit them.
+		var extensionsPresent bool
+		bWithoutExtensions := *b
+
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			if m.ocspStapling {
+				b.AddUint16(extensionStatusRequest)
+				b.AddUint16(0) // empty extension_data
+			}
+			if m.ticketSupported {
+				b.AddUint16(extensionSessionTicket)
+				b.AddUint16(0) // empty extension_data
+			}
+			if m.secureRenegotiationSupported {
+				b.AddUint16(extensionRenegotiationInfo)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(m.secureRenegotiation)
+					})
+				})
+			}
+			if len(m.alpnProtocol) > 0 {
+				b.AddUint16(extensionALPN)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+							b.AddBytes([]byte(m.alpnProtocol))
+						})
+					})
+				})
+			}
+			if len(m.scts) > 0 {
+				b.AddUint16(extensionSCT)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, sct := range m.scts {
+							b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+								b.AddBytes(sct)
+							})
+						}
+					})
+				})
+			}
+			if m.supportedVersion != 0 {
+				b.AddUint16(extensionSupportedVersions)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16(m.supportedVersion)
+				})
+			}
+			if m.serverShare.group != 0 {
+				b.AddUint16(extensionKeyShare)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16(uint16(m.serverShare.group))
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(m.serverShare.data)
+					})
+				})
+			}
+			if m.selectedIdentityPresent {
+				b.AddUint16(extensionPreSharedKey)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16(m.selectedIdentity)
+				})
+			}
+
+			if len(m.cookie) > 0 {
+				b.AddUint16(extensionCookie)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(m.cookie)
+					})
+				})
+			}
+			if m.selectedGroup != 0 {
+				b.AddUint16(extensionKeyShare)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16(uint16(m.selectedGroup))
+				})
+			}
+			if len(m.supportedPoints) > 0 {
+				b.AddUint16(extensionSupportedPoints)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(m.supportedPoints)
+					})
+				})
+			}
+			if len(m.ech) > 0 {
+				// draft-ietf-tls-esni-13, "encrypted_client_hello"
+				b.AddUint16(extensionECH)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddBytes(m.ech)
+				})
+			}
+
+			extensionsPresent = len(b.BytesOrPanic()) > 2
+		})
+
+		if !extensionsPresent {
+			*b = bWithoutExtensions
+		}
+	})
+
+	m.raw = b.BytesOrPanic()
+	return m.raw
+}
+
+func (m *serverHelloMsg) unmarshal(data []byte) bool {
+	*m = serverHelloMsg{raw: data}
+	s := cryptobyte.String(data)
+
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) ||
+		!readUint8LengthPrefixed(&s, &m.sessionId) ||
+		!s.ReadUint16(&m.cipherSuite) ||
+		!s.ReadUint8(&m.compressionMethod) {
+		return false
+	}
+
+	if s.Empty() {
+		// ServerHello is optionally followed by extension data
+		return true
+	}
+
+	var extensions cryptobyte.String
+	if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+		return false
+	}
+
+	for !extensions.Empty() {
+		var extension uint16
+		var extData cryptobyte.String
+		if !extensions.ReadUint16(&extension) ||
+			!extensions.ReadUint16LengthPrefixed(&extData) {
+			return false
+		}
+
+		switch extension {
+		case extensionStatusRequest:
+			m.ocspStapling = true
+		case extensionSessionTicket:
+			m.ticketSupported = true
+		case extensionRenegotiationInfo:
+			if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) {
+				return false
+			}
+			m.secureRenegotiationSupported = true
+		case extensionALPN:
+			var protoList cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+				return false
+			}
+			var proto cryptobyte.String
+			if !protoList.ReadUint8LengthPrefixed(&proto) ||
+				proto.Empty() || !protoList.Empty() {
+				return false
+			}
+			m.alpnProtocol = string(proto)
+		case extensionSCT:
+			var sctList cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() {
+				return false
+			}
+			for !sctList.Empty() {
+				var sct []byte
+				if !readUint16LengthPrefixed(&sctList, &sct) ||
+					len(sct) == 0 {
+					return false
+				}
+				m.scts = append(m.scts, sct)
+			}
+		case extensionSupportedVersions:
+			if !extData.ReadUint16(&m.supportedVersion) {
+				return false
+			}
+		case extensionCookie:
+			if !readUint16LengthPrefixed(&extData, &m.cookie) ||
+				len(m.cookie) == 0 {
+				return false
+			}
+		case extensionKeyShare:
+			// This extension has different formats in SH and HRR, accept either
+			// and let the handshake logic decide. See RFC 8446, Section 4.2.8.
+			if len(extData) == 2 {
+				if !extData.ReadUint16((*uint16)(&m.selectedGroup)) {
+					return false
+				}
+			} else {
+				if !extData.ReadUint16((*uint16)(&m.serverShare.group)) ||
+					!readUint16LengthPrefixed(&extData, &m.serverShare.data) {
+					return false
+				}
+			}
+		case extensionPreSharedKey:
+			m.selectedIdentityPresent = true
+			if !extData.ReadUint16(&m.selectedIdentity) {
+				return false
+			}
+		case extensionSupportedPoints:
+			// RFC 4492, Section 5.1.2
+			if !readUint8LengthPrefixed(&extData, &m.supportedPoints) ||
+				len(m.supportedPoints) == 0 {
+				return false
+			}
+		case extensionECH:
+			// draft-ietf-tls-esni-13, "encrypted_client_hello"
+			if !extData.ReadBytes(&m.ech, len(extData)) {
+				return false
+			}
+		default:
+			// Ignore unknown extensions.
+			continue
+		}
+
+		if !extData.Empty() {
+			return false
+		}
+	}
+
+	return true
+}
+
+type encryptedExtensionsMsg struct {
+	raw          []byte
+	alpnProtocol string
+	ech          []byte
+}
+
+func (m *encryptedExtensionsMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeEncryptedExtensions)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			if len(m.alpnProtocol) > 0 {
+				b.AddUint16(extensionALPN)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+							b.AddBytes([]byte(m.alpnProtocol))
+						})
+					})
+				})
+			}
+			if len(m.ech) > 0 {
+				// draft-ietf-tls-esni-13, "encrypted_client_hello"
+				b.AddUint16(extensionECH)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					// If the client-facing server rejects ECH, then it may
+					// sends retry configurations here.
+					b.AddBytes(m.ech)
+				})
+			}
+		})
+	})
+
+	m.raw = b.BytesOrPanic()
+	return m.raw
+}
+
+func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
+	*m = encryptedExtensionsMsg{raw: data}
+	s := cryptobyte.String(data)
+
+	var extensions cryptobyte.String
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+		return false
+	}
+
+	for !extensions.Empty() {
+		var extension uint16
+		var extData cryptobyte.String
+		if !extensions.ReadUint16(&extension) ||
+			!extensions.ReadUint16LengthPrefixed(&extData) {
+			return false
+		}
+
+		switch extension {
+		case extensionALPN:
+			var protoList cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+				return false
+			}
+			var proto cryptobyte.String
+			if !protoList.ReadUint8LengthPrefixed(&proto) ||
+				proto.Empty() || !protoList.Empty() {
+				return false
+			}
+			m.alpnProtocol = string(proto)
+		case extensionECH:
+			// draft-ietf-tls-esni-13
+			if !extData.ReadBytes(&m.ech, len(extData)) {
+				return false
+			}
+		default:
+			// Ignore unknown extensions.
+			continue
+		}
+
+		if !extData.Empty() {
+			return false
+		}
+	}
+
+	return true
+}
+
+type endOfEarlyDataMsg struct{}
+
+func (m *endOfEarlyDataMsg) marshal() []byte {
+	x := make([]byte, 4)
+	x[0] = typeEndOfEarlyData
+	return x
+}
+
+func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}
+
+type keyUpdateMsg struct {
+	raw             []byte
+	updateRequested bool
+}
+
+func (m *keyUpdateMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeKeyUpdate)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		if m.updateRequested {
+			b.AddUint8(1)
+		} else {
+			b.AddUint8(0)
+		}
+	})
+
+	m.raw = b.BytesOrPanic()
+	return m.raw
+}
+
+func (m *keyUpdateMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	s := cryptobyte.String(data)
+
+	var updateRequested uint8
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint8(&updateRequested) || !s.Empty() {
+		return false
+	}
+	switch updateRequested {
+	case 0:
+		m.updateRequested = false
+	case 1:
+		m.updateRequested = true
+	default:
+		return false
+	}
+	return true
+}
+
+type newSessionTicketMsgTLS13 struct {
+	raw          []byte
+	lifetime     uint32
+	ageAdd       uint32
+	nonce        []byte
+	label        []byte
+	maxEarlyData uint32
+}
+
+func (m *newSessionTicketMsgTLS13) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeNewSessionTicket)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint32(m.lifetime)
+		b.AddUint32(m.ageAdd)
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(m.nonce)
+		})
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(m.label)
+		})
+
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			if m.maxEarlyData > 0 {
+				b.AddUint16(extensionEarlyData)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint32(m.maxEarlyData)
+				})
+			}
+		})
+	})
+
+	m.raw = b.BytesOrPanic()
+	return m.raw
+}
+
+func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool {
+	*m = newSessionTicketMsgTLS13{raw: data}
+	s := cryptobyte.String(data)
+
+	var extensions cryptobyte.String
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint32(&m.lifetime) ||
+		!s.ReadUint32(&m.ageAdd) ||
+		!readUint8LengthPrefixed(&s, &m.nonce) ||
+		!readUint16LengthPrefixed(&s, &m.label) ||
+		!s.ReadUint16LengthPrefixed(&extensions) ||
+		!s.Empty() {
+		return false
+	}
+
+	for !extensions.Empty() {
+		var extension uint16
+		var extData cryptobyte.String
+		if !extensions.ReadUint16(&extension) ||
+			!extensions.ReadUint16LengthPrefixed(&extData) {
+			return false
+		}
+
+		switch extension {
+		case extensionEarlyData:
+			if !extData.ReadUint32(&m.maxEarlyData) {
+				return false
+			}
+		default:
+			// Ignore unknown extensions.
+			continue
+		}
+
+		if !extData.Empty() {
+			return false
+		}
+	}
+
+	return true
+}
+
+type certificateRequestMsgTLS13 struct {
+	raw                              []byte
+	ocspStapling                     bool
+	scts                             bool
+	supportDelegatedCredential       bool
+	supportedSignatureAlgorithms     []SignatureScheme
+	supportedSignatureAlgorithmsDC   []SignatureScheme
+	supportedSignatureAlgorithmsCert []SignatureScheme
+	certificateAuthorities           [][]byte
+}
+
+func (m *certificateRequestMsgTLS13) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeCertificateRequest)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		// certificate_request_context (SHALL be zero length unless used for
+		// post-handshake authentication)
+		b.AddUint8(0)
+
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			if m.ocspStapling {
+				b.AddUint16(extensionStatusRequest)
+				b.AddUint16(0) // empty extension_data
+			}
+			if m.scts {
+				// RFC 8446, Section 4.4.2.1 makes no mention of
+				// signed_certificate_timestamp in CertificateRequest, but
+				// "Extensions in the Certificate message from the client MUST
+				// correspond to extensions in the CertificateRequest message
+				// from the server." and it appears in the table in Section 4.2.
+				b.AddUint16(extensionSCT)
+				b.AddUint16(0) // empty extension_data
+			}
+			if m.supportDelegatedCredential {
+				if len(m.supportedSignatureAlgorithmsDC) > 0 {
+					// Draft: https://tools.ietf.org/html/draft-ietf-tls-subcerts-10
+					b.AddUint16(extensionDelegatedCredentials)
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+							for _, sigAlgo := range m.supportedSignatureAlgorithmsDC {
+								b.AddUint16(uint16(sigAlgo))
+							}
+						})
+					})
+				}
+			}
+			if len(m.supportedSignatureAlgorithms) > 0 {
+				b.AddUint16(extensionSignatureAlgorithms)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, sigAlgo := range m.supportedSignatureAlgorithms {
+							b.AddUint16(uint16(sigAlgo))
+						}
+					})
+				})
+			}
+			if len(m.supportedSignatureAlgorithmsCert) > 0 {
+				b.AddUint16(extensionSignatureAlgorithmsCert)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
+							b.AddUint16(uint16(sigAlgo))
+						}
+					})
+				})
+			}
+			if len(m.certificateAuthorities) > 0 {
+				b.AddUint16(extensionCertificateAuthorities)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						for _, ca := range m.certificateAuthorities {
+							b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+								b.AddBytes(ca)
+							})
+						}
+					})
+				})
+			}
+		})
+	})
+
+	m.raw = b.BytesOrPanic()
+	return m.raw
+}
+
+func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool {
+	*m = certificateRequestMsgTLS13{raw: data}
+	s := cryptobyte.String(data)
+
+	var context, extensions cryptobyte.String
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint8LengthPrefixed(&context) || !context.Empty() ||
+		!s.ReadUint16LengthPrefixed(&extensions) ||
+		!s.Empty() {
+		return false
+	}
+
+	for !extensions.Empty() {
+		var extension uint16
+		var extData cryptobyte.String
+		if !extensions.ReadUint16(&extension) ||
+			!extensions.ReadUint16LengthPrefixed(&extData) {
+			return false
+		}
+
+		switch extension {
+		case extensionStatusRequest:
+			m.ocspStapling = true
+		case extensionSCT:
+			m.scts = true
+		case extensionDelegatedCredentials:
+			var sigAndAlgs cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+				return false
+			}
+			for !sigAndAlgs.Empty() {
+				var sigAndAlg uint16
+				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+					return false
+				}
+				m.supportedSignatureAlgorithmsDC = append(
+					m.supportedSignatureAlgorithmsDC, SignatureScheme(sigAndAlg))
+			}
+			m.supportDelegatedCredential = true
+		case extensionSignatureAlgorithms:
+			var sigAndAlgs cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+				return false
+			}
+			for !sigAndAlgs.Empty() {
+				var sigAndAlg uint16
+				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+					return false
+				}
+				m.supportedSignatureAlgorithms = append(
+					m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
+			}
+		case extensionSignatureAlgorithmsCert:
+			var sigAndAlgs cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+				return false
+			}
+			for !sigAndAlgs.Empty() {
+				var sigAndAlg uint16
+				if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+					return false
+				}
+				m.supportedSignatureAlgorithmsCert = append(
+					m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg))
+			}
+		case extensionCertificateAuthorities:
+			var auths cryptobyte.String
+			if !extData.ReadUint16LengthPrefixed(&auths) || auths.Empty() {
+				return false
+			}
+			for !auths.Empty() {
+				var ca []byte
+				if !readUint16LengthPrefixed(&auths, &ca) || len(ca) == 0 {
+					return false
+				}
+				m.certificateAuthorities = append(m.certificateAuthorities, ca)
+			}
+		default:
+			// Ignore unknown extensions.
+			continue
+		}
+
+		if !extData.Empty() {
+			return false
+		}
+	}
+
+	return true
+}
+
+type certificateMsg struct {
+	raw          []byte
+	certificates [][]byte
+}
+
+func (m *certificateMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var i int
+	for _, slice := range m.certificates {
+		i += len(slice)
+	}
+
+	length := 3 + 3*len(m.certificates) + i
+	x = make([]byte, 4+length)
+	x[0] = typeCertificate
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	certificateOctets := length - 3
+	x[4] = uint8(certificateOctets >> 16)
+	x[5] = uint8(certificateOctets >> 8)
+	x[6] = uint8(certificateOctets)
+
+	y := x[7:]
+	for _, slice := range m.certificates {
+		y[0] = uint8(len(slice) >> 16)
+		y[1] = uint8(len(slice) >> 8)
+		y[2] = uint8(len(slice))
+		copy(y[3:], slice)
+		y = y[3+len(slice):]
+	}
+
+	m.raw = x
+	return
+}
+
+func (m *certificateMsg) unmarshal(data []byte) bool {
+	if len(data) < 7 {
+		return false
+	}
+
+	m.raw = data
+	certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
+	if uint32(len(data)) != certsLen+7 {
+		return false
+	}
+
+	numCerts := 0
+	d := data[7:]
+	for certsLen > 0 {
+		if len(d) < 4 {
+			return false
+		}
+		certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+		if uint32(len(d)) < 3+certLen {
+			return false
+		}
+		d = d[3+certLen:]
+		certsLen -= 3 + certLen
+		numCerts++
+	}
+
+	m.certificates = make([][]byte, numCerts)
+	d = data[7:]
+	for i := 0; i < numCerts; i++ {
+		certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+		m.certificates[i] = d[3 : 3+certLen]
+		d = d[3+certLen:]
+	}
+
+	return true
+}
+
+type certificateMsgTLS13 struct {
+	raw                 []byte
+	certificate         Certificate
+	ocspStapling        bool
+	scts                bool
+	delegatedCredential bool
+}
+
+func (m *certificateMsgTLS13) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeCertificate)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint8(0) // certificate_request_context
+
+		certificate := m.certificate
+		if !m.ocspStapling {
+			certificate.OCSPStaple = nil
+		}
+		if !m.scts {
+			certificate.SignedCertificateTimestamps = nil
+		}
+		if !m.delegatedCredential {
+			certificate.DelegatedCredential = nil
+		}
+		marshalCertificate(b, certificate)
+	})
+
+	m.raw = b.BytesOrPanic()
+
+	return m.raw
+}
+
+func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) {
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		for i, cert := range certificate.Certificate {
+			b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+				b.AddBytes(cert)
+			})
+			b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+				if i > 0 {
+					// This library only supports OCSP, SCT and Delegated Credentials for leaf certificates.
+					// Delegated Credentials are only supported on the leaf/end-entity certificate.
+					return
+				}
+				if certificate.OCSPStaple != nil {
+					b.AddUint16(extensionStatusRequest)
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddUint8(statusTypeOCSP)
+						b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+							b.AddBytes(certificate.OCSPStaple)
+						})
+					})
+				}
+				if certificate.SignedCertificateTimestamps != nil {
+					b.AddUint16(extensionSCT)
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+							for _, sct := range certificate.SignedCertificateTimestamps {
+								b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+									b.AddBytes(sct)
+								})
+							}
+						})
+					})
+				}
+				if certificate.DelegatedCredential != nil {
+					b.AddUint16(extensionDelegatedCredentials)
+					b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(certificate.DelegatedCredential)
+					})
+				}
+			})
+		}
+	})
+}
+
+func (m *certificateMsgTLS13) unmarshal(data []byte) bool {
+	*m = certificateMsgTLS13{raw: data}
+	s := cryptobyte.String(data)
+
+	var context cryptobyte.String
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint8LengthPrefixed(&context) || !context.Empty() ||
+		!unmarshalCertificate(&s, &m.certificate) ||
+		!s.Empty() {
+		return false
+	}
+
+	m.scts = m.certificate.SignedCertificateTimestamps != nil
+	m.ocspStapling = m.certificate.OCSPStaple != nil
+	m.delegatedCredential = m.certificate.DelegatedCredential != nil
+
+	return true
+}
+
+func unmarshalCertificate(s *cryptobyte.String, certificate *Certificate) bool {
+	var certList cryptobyte.String
+	if !s.ReadUint24LengthPrefixed(&certList) {
+		return false
+	}
+	for !certList.Empty() {
+		var cert []byte
+		var extensions cryptobyte.String
+		if !readUint24LengthPrefixed(&certList, &cert) ||
+			!certList.ReadUint16LengthPrefixed(&extensions) {
+			return false
+		}
+		certificate.Certificate = append(certificate.Certificate, cert)
+		for !extensions.Empty() {
+			var extension uint16
+			var extData cryptobyte.String
+			if !extensions.ReadUint16(&extension) ||
+				!extensions.ReadUint16LengthPrefixed(&extData) {
+				return false
+			}
+			if len(certificate.Certificate) > 1 {
+				// This library only supports OCSP and SCT for leaf certificates.
+				continue
+			}
+
+			switch extension {
+			case extensionStatusRequest:
+				var statusType uint8
+				if !extData.ReadUint8(&statusType) || statusType != statusTypeOCSP ||
+					!readUint24LengthPrefixed(&extData, &certificate.OCSPStaple) ||
+					len(certificate.OCSPStaple) == 0 {
+					return false
+				}
+			case extensionSCT:
+				var sctList cryptobyte.String
+				if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() {
+					return false
+				}
+				for !sctList.Empty() {
+					var sct []byte
+					if !readUint16LengthPrefixed(&sctList, &sct) ||
+						len(sct) == 0 {
+						return false
+					}
+					certificate.SignedCertificateTimestamps = append(
+						certificate.SignedCertificateTimestamps, sct)
+				}
+			case extensionDelegatedCredentials:
+				if !extData.ReadBytes(&certificate.DelegatedCredential, len(extData)) {
+					return false
+				}
+				if len(certificate.DelegatedCredential) == 0 {
+					return false
+				}
+			default:
+				// Ignore unknown extensions.
+				continue
+			}
+
+			if !extData.Empty() {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+type serverKeyExchangeMsg struct {
+	raw []byte
+	key []byte
+}
+
+func (m *serverKeyExchangeMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+	length := len(m.key)
+	x := make([]byte, length+4)
+	x[0] = typeServerKeyExchange
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	copy(x[4:], m.key)
+
+	m.raw = x
+	return x
+}
+
+func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	if len(data) < 4 {
+		return false
+	}
+	m.key = data[4:]
+	return true
+}
+
+type certificateStatusMsg struct {
+	raw      []byte
+	response []byte
+}
+
+func (m *certificateStatusMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeCertificateStatus)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddUint8(statusTypeOCSP)
+		b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(m.response)
+		})
+	})
+
+	m.raw = b.BytesOrPanic()
+	return m.raw
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	s := cryptobyte.String(data)
+
+	var statusType uint8
+	if !s.Skip(4) || // message type and uint24 length field
+		!s.ReadUint8(&statusType) || statusType != statusTypeOCSP ||
+		!readUint24LengthPrefixed(&s, &m.response) ||
+		len(m.response) == 0 || !s.Empty() {
+		return false
+	}
+	return true
+}
+
+type serverHelloDoneMsg struct{}
+
+func (m *serverHelloDoneMsg) marshal() []byte {
+	x := make([]byte, 4)
+	x[0] = typeServerHelloDone
+	return x
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}
+
+type clientKeyExchangeMsg struct {
+	raw        []byte
+	ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+	length := len(m.ciphertext)
+	x := make([]byte, length+4)
+	x[0] = typeClientKeyExchange
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	copy(x[4:], m.ciphertext)
+
+	m.raw = x
+	return x
+}
+
+func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	if len(data) < 4 {
+		return false
+	}
+	l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+	if l != len(data)-4 {
+		return false
+	}
+	m.ciphertext = data[4:]
+	return true
+}
+
+type finishedMsg struct {
+	raw        []byte
+	verifyData []byte
+}
+
+func (m *finishedMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeFinished)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(m.verifyData)
+	})
+
+	m.raw = b.BytesOrPanic()
+	return m.raw
+}
+
+func (m *finishedMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	s := cryptobyte.String(data)
+	return s.Skip(1) &&
+		readUint24LengthPrefixed(&s, &m.verifyData) &&
+		s.Empty()
+}
+
+type certificateRequestMsg struct {
+	raw []byte
+	// hasSignatureAlgorithm indicates whether this message includes a list of
+	// supported signature algorithms. This change was introduced with TLS 1.2.
+	hasSignatureAlgorithm bool
+
+	certificateTypes             []byte
+	supportedSignatureAlgorithms []SignatureScheme
+	certificateAuthorities       [][]byte
+}
+
+func (m *certificateRequestMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See RFC 4346, Section 7.4.4.
+	length := 1 + len(m.certificateTypes) + 2
+	casLength := 0
+	for _, ca := range m.certificateAuthorities {
+		casLength += 2 + len(ca)
+	}
+	length += casLength
+
+	if m.hasSignatureAlgorithm {
+		length += 2 + 2*len(m.supportedSignatureAlgorithms)
+	}
+
+	x = make([]byte, 4+length)
+	x[0] = typeCertificateRequest
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+
+	x[4] = uint8(len(m.certificateTypes))
+
+	copy(x[5:], m.certificateTypes)
+	y := x[5+len(m.certificateTypes):]
+
+	if m.hasSignatureAlgorithm {
+		n := len(m.supportedSignatureAlgorithms) * 2
+		y[0] = uint8(n >> 8)
+		y[1] = uint8(n)
+		y = y[2:]
+		for _, sigAlgo := range m.supportedSignatureAlgorithms {
+			y[0] = uint8(sigAlgo >> 8)
+			y[1] = uint8(sigAlgo)
+			y = y[2:]
+		}
+	}
+
+	y[0] = uint8(casLength >> 8)
+	y[1] = uint8(casLength)
+	y = y[2:]
+	for _, ca := range m.certificateAuthorities {
+		y[0] = uint8(len(ca) >> 8)
+		y[1] = uint8(len(ca))
+		y = y[2:]
+		copy(y, ca)
+		y = y[len(ca):]
+	}
+
+	m.raw = x
+	return
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+	m.raw = data
+
+	if len(data) < 5 {
+		return false
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return false
+	}
+
+	numCertTypes := int(data[4])
+	data = data[5:]
+	if numCertTypes == 0 || len(data) <= numCertTypes {
+		return false
+	}
+
+	m.certificateTypes = make([]byte, numCertTypes)
+	if copy(m.certificateTypes, data) != numCertTypes {
+		return false
+	}
+
+	data = data[numCertTypes:]
+
+	if m.hasSignatureAlgorithm {
+		if len(data) < 2 {
+			return false
+		}
+		sigAndHashLen := uint16(data[0])<<8 | uint16(data[1])
+		data = data[2:]
+		if sigAndHashLen&1 != 0 {
+			return false
+		}
+		if len(data) < int(sigAndHashLen) {
+			return false
+		}
+		numSigAlgos := sigAndHashLen / 2
+		m.supportedSignatureAlgorithms = make([]SignatureScheme, numSigAlgos)
+		for i := range m.supportedSignatureAlgorithms {
+			m.supportedSignatureAlgorithms[i] = SignatureScheme(data[0])<<8 | SignatureScheme(data[1])
+			data = data[2:]
+		}
+	}
+
+	if len(data) < 2 {
+		return false
+	}
+	casLength := uint16(data[0])<<8 | uint16(data[1])
+	data = data[2:]
+	if len(data) < int(casLength) {
+		return false
+	}
+	cas := make([]byte, casLength)
+	copy(cas, data)
+	data = data[casLength:]
+
+	m.certificateAuthorities = nil
+	for len(cas) > 0 {
+		if len(cas) < 2 {
+			return false
+		}
+		caLen := uint16(cas[0])<<8 | uint16(cas[1])
+		cas = cas[2:]
+
+		if len(cas) < int(caLen) {
+			return false
+		}
+
+		m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
+		cas = cas[caLen:]
+	}
+
+	return len(data) == 0
+}
+
+type certificateVerifyMsg struct {
+	raw                   []byte
+	hasSignatureAlgorithm bool // format change introduced in TLS 1.2
+	signatureAlgorithm    SignatureScheme
+	signature             []byte
+}
+
+func (m *certificateVerifyMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeCertificateVerify)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		if m.hasSignatureAlgorithm {
+			b.AddUint16(uint16(m.signatureAlgorithm))
+		}
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(m.signature)
+		})
+	})
+
+	m.raw = b.BytesOrPanic()
+	return m.raw
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
+	m.raw = data
+	s := cryptobyte.String(data)
+
+	if !s.Skip(4) { // message type and uint24 length field
+		return false
+	}
+	if m.hasSignatureAlgorithm {
+		if !s.ReadUint16((*uint16)(&m.signatureAlgorithm)) {
+			return false
+		}
+	}
+	return readUint16LengthPrefixed(&s, &m.signature) && s.Empty()
+}
+
+type newSessionTicketMsg struct {
+	raw    []byte
+	ticket []byte
+}
+
+func (m *newSessionTicketMsg) marshal() (x []byte) {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// See RFC 5077, Section 3.3.
+	ticketLen := len(m.ticket)
+	length := 2 + 4 + ticketLen
+	x = make([]byte, 4+length)
+	x[0] = typeNewSessionTicket
+	x[1] = uint8(length >> 16)
+	x[2] = uint8(length >> 8)
+	x[3] = uint8(length)
+	x[8] = uint8(ticketLen >> 8)
+	x[9] = uint8(ticketLen)
+	copy(x[10:], m.ticket)
+
+	m.raw = x
+
+	return
+}
+
+func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
+	m.raw = data
+
+	if len(data) < 10 {
+		return false
+	}
+
+	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+	if uint32(len(data))-4 != length {
+		return false
+	}
+
+	ticketLen := int(data[8])<<8 + int(data[9])
+	if len(data)-10 != ticketLen {
+		return false
+	}
+
+	m.ticket = data[10:]
+
+	return true
+}
+
+type helloRequestMsg struct{}
+
+func (*helloRequestMsg) marshal() []byte {
+	return []byte{typeHelloRequest, 0, 0, 0}
+}
+
+func (*helloRequestMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}

+ 893 - 0
transport/cloudflaretls/handshake_server.go

@@ -0,0 +1,893 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"context"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/rsa"
+	"crypto/subtle"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"hash"
+	"io"
+	"sync/atomic"
+	"time"
+
+	circlSign "github.com/cloudflare/circl/sign"
+)
+
+// 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 {
+	clientHello, err := c.readClientHello(ctx)
+	if err != nil {
+		return err
+	}
+
+	if c.vers == VersionTLS13 {
+		hs := serverHandshakeStateTLS13{
+			c:           c,
+			ctx:         ctx,
+			clientHello: clientHello,
+			hsTimings:   createTLS13ServerHandshakeTimingInfo(c.config.Time),
+		}
+		return hs.handshake()
+	}
+
+	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)
+
+	return nil
+}
+
+// readClientHello reads a ClientHello message and selects the protocol version.
+func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
+	msg, err := c.readHandshake()
+	if err != nil {
+		return nil, err
+	}
+	clientHello, ok := msg.(*clientHelloMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return nil, unexpectedMessageError(clientHello, msg)
+	}
+
+	// NOTE(cjpatton): ECH usage is resolved before calling GetConfigForClient()
+	// or GetCertifciate(). Hence, it is not currently possible to reject ECH if
+	// we don't recognize the inner SNI. This may or may not be desirable in the
+	// future.
+	clientHello, err = c.echAcceptOrReject(clientHello, false) // afterHRR == false
+	if err != nil {
+		return nil, fmt.Errorf("tls: %s", err) // Alert sent.
+	}
+
+	var configForClient *Config
+	originalConfig := c.config
+	if c.config.GetConfigForClient != nil {
+		chi := clientHelloInfo(ctx, c, clientHello)
+		if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
+			c.sendAlert(alertInternalError)
+			return nil, err
+		} else if configForClient != nil {
+			c.config = configForClient
+		}
+	}
+	c.ticketKeys = originalConfig.ticketKeys(configForClient)
+
+	clientVersions := clientHello.supportedVersions
+	if len(clientHello.supportedVersions) == 0 {
+		clientVersions = supportedVersionsFromMax(clientHello.vers)
+	}
+	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(clientHelloInfo(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 {
+		// 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
+		}
+	}
+
+	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 || c.config.ECHEnabled {
+		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()
+	hs.finishedHash.Write(hs.clientHello.marshal())
+	hs.finishedHash.Write(hs.hello.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); 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 && !c.config.ECHEnabled
+	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()
+	}
+	hs.finishedHash.Write(hs.clientHello.marshal())
+	hs.finishedHash.Write(hs.hello.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+		return err
+	}
+
+	certMsg := new(certificateMsg)
+	certMsg.certificates = hs.cert.Certificate
+	hs.finishedHash.Write(certMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+		return err
+	}
+
+	if hs.hello.ocspStapling {
+		certStatus := new(certificateStatusMsg)
+		certStatus.response = hs.cert.OCSPStaple
+		hs.finishedHash.Write(certStatus.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); 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 {
+		hs.finishedHash.Write(skx.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); 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 = c.config.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()
+		}
+		hs.finishedHash.Write(certReq.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
+			return err
+		}
+	}
+
+	helloDone := new(serverHelloDoneMsg)
+	hs.finishedHash.Write(helloDone.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); 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()
+	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)
+		}
+		hs.finishedHash.Write(certMsg.marshal())
+
+		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()
+		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)
+	}
+	hs.finishedHash.Write(ckx.marshal())
+
+	preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	if eccKex, ok := keyAgreement.(*ecdheKeyAgreement); ok {
+		c.handleCFEvent(CFEventTLSNegotiatedNamedKEX{
+			KEX: eccKex.params.CurveID(),
+		})
+	}
+	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 {
+		msg, err = c.readHandshake()
+		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())
+		}
+
+		hs.finishedHash.Write(certVerify.marshal())
+	}
+
+	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
+	}
+
+	msg, err := c.readHandshake()
+	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")
+	}
+
+	hs.finishedHash.Write(clientFinished.marshal())
+	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,
+	}
+	var err error
+	m.ticket, err = c.encryptTicket(state.marshal())
+	if err != nil {
+		return err
+	}
+
+	hs.finishedHash.Write(m.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeState) sendFinished(out []byte) error {
+	c := hs.c
+
+	if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+		return err
+	}
+
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+	hs.finishedHash.Write(finished.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); 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, circlSign.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 clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
+	supportedVersions := clientHello.supportedVersions
+	if len(clientHello.supportedVersions) == 0 {
+		supportedVersions = supportedVersionsFromMax(clientHello.vers)
+	}
+
+	return &ClientHelloInfo{
+		CipherSuites:                clientHello.cipherSuites,
+		ServerName:                  clientHello.serverName,
+		SupportedCurves:             clientHello.supportedCurves,
+		SupportedPoints:             clientHello.supportedPoints,
+		SignatureSchemes:            clientHello.supportedSignatureAlgorithms,
+		SupportedProtos:             clientHello.alpnProtocols,
+		SupportedVersions:           supportedVersions,
+		SupportsDelegatedCredential: clientHello.delegatedCredentialSupported,
+		SignatureSchemesDC:          clientHello.supportedSignatureAlgorithmsDC,
+		Conn:                        c.conn,
+		config:                      c.config,
+		ctx:                         ctx,
+	}
+}

+ 1121 - 0
transport/cloudflaretls/handshake_server_tls13.go

@@ -0,0 +1,1121 @@
+// 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 tls
+
+import (
+	"bytes"
+	"context"
+	"crypto"
+	"crypto/hmac"
+	"crypto/rsa"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"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
+	sentDummyCCS    bool
+	usingPSK        bool
+	suite           *cipherSuiteTLS13
+	cert            *Certificate
+	sigAlg          SignatureScheme
+	selectedGroup   CurveID
+	earlySecret     []byte
+	sharedKey       []byte
+	handshakeSecret []byte
+	masterSecret    []byte
+	trafficSecret   []byte // client_application_traffic_secret_0
+	transcript      hash.Hash
+	clientFinished  []byte
+	certReq         *certificateRequestMsgTLS13
+
+	hsTimings CFEventTLS13ServerHandshakeTimingInfo
+}
+
+func (hs *serverHandshakeStateTLS13) echIsInner() bool {
+	return len(hs.clientHello.ech) == 1 && hs.clientHello.ech[0] == echClientHelloInnerVariant
+}
+
+// processDelegatedCredentialFromClient unmarshals the DelegatedCredential
+// offered by the client (if present) and validates it using the peer's
+// certificate.
+func (hs *serverHandshakeStateTLS13) processDelegatedCredentialFromClient(rawDC []byte, certVerifyMsg *certificateVerifyMsg) error {
+	c := hs.c
+
+	var dc *DelegatedCredential
+	var err error
+	if rawDC != nil {
+		// Assert that the DC extension was indicated by the client.
+		if !hs.certReq.supportDelegatedCredential {
+			c.sendAlert(alertUnexpectedMessage)
+			return errors.New("tls: got Delegated Credential extension without indication")
+		}
+
+		dc, err = UnmarshalDelegatedCredential(rawDC)
+		if err != nil {
+			c.sendAlert(alertDecodeError)
+			return fmt.Errorf("tls: Delegated Credential: %s", err)
+		}
+
+		if !isSupportedSignatureAlgorithm(dc.cred.expCertVerfAlgo, supportedSignatureAlgorithmsDC) {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: Delegated Credential used with invalid signature algorithm")
+		}
+	}
+
+	if dc != nil {
+		if !dc.Validate(c.peerCertificates[0], true, c.config.time(), certVerifyMsg) {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: invalid Delegated Credential")
+		}
+	}
+
+	c.verifiedDC = dc
+
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) handshake() error {
+	c := hs.c
+
+	// 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
+	}
+	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
+	}
+	if err := hs.readClientFinished(); err != nil {
+		return err
+	}
+
+	c.handleCFEvent(hs.hsTimings)
+	atomic.StoreUint32(&c.handshakeStatus, 1)
+
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) processClientHello() error {
+	c := hs.c
+
+	hs.hello = new(serverHelloMsg)
+
+	// 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")
+	}
+
+	if hs.clientHello.earlyData {
+		// See RFC 8446, Section 4.2.10 for the complicated behavior required
+		// here. The scenario is that a different server at our address offered
+		// to accept early data in the past, which we can't handle. For now, all
+		// 0-RTT enabled session tickets need to expire before a Go server can
+		// replace a server or join a pool. That's the same requirement that
+		// applies to mixing or replacing with any TLS 1.2 server.
+		c.sendAlert(alertUnsupportedExtension)
+		return errors.New("tls: client sent unexpected early data")
+	}
+
+	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()
+
+	// Resolve the server's preference for the ECDHE group.
+	supportedCurves := c.config.curvePreferences()
+	if testingTriggerHRR {
+		// A HelloRetryRequest (HRR) is sent if the client does not offer a key
+		// share for a curve supported by the server. To trigger this condition
+		// intentionally, we compute the set of ECDHE groups supported by both
+		// the client and server but for which the client did not offer a key
+		// share.
+		m := make(map[CurveID]bool)
+		for _, serverGroup := range c.config.curvePreferences() {
+			for _, clientGroup := range hs.clientHello.supportedCurves {
+				if clientGroup == serverGroup {
+					m[clientGroup] = true
+				}
+			}
+		}
+		for _, ks := range hs.clientHello.keyShares {
+			delete(m, ks.group)
+		}
+		supportedCurves = nil
+		for group := range m {
+			supportedCurves = append(supportedCurves, group)
+		}
+		if len(supportedCurves) == 0 {
+			// This occurs if the client offered a key share for each mutually
+			// supported group.
+			panic("failed to trigger HelloRetryRequest")
+		}
+	}
+
+	// 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 supportedCurves {
+		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 && curveIdToCirclScheme(selectedGroup) == nil && !ok {
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: CurvePreferences includes unsupported curve")
+	}
+	if kem := curveIdToCirclScheme(selectedGroup); kem != nil {
+		ct, ss, alert, err := encapsulateForKem(kem, c.config.rand(), clientKeyShare.data)
+		if err != nil {
+			c.sendAlert(alert)
+			return fmt.Errorf("%s encap: %w", kem.Name(), err)
+		}
+		hs.hello.serverShare = keyShare{group: selectedGroup, data: ct}
+		hs.sharedKey = ss
+	} else {
+		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
+	c.handleCFEvent(CFEventTLSNegotiatedNamedKEX{
+		KEX: selectedGroup,
+	})
+
+	hs.hsTimings.ProcessClientHello = hs.hsTimings.elapsedTime()
+
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) checkForResumption() error {
+	c := hs.c
+
+	if c.config.SessionTicketsDisabled || c.config.ECHEnabled {
+		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
+		}
+
+		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")
+		}
+		transcript.Write(hs.clientHello.marshalWithoutBinders())
+		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
+		}
+
+		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
+}
+
+// getDelegatedCredential will return a Delegated Credential pair (a Delegated
+// Credential and its private key) for the given ClientHelloInfo, defaulting to
+// the first element of cert.DelegatedCredentialPair.
+// The returned Delegated Credential could be invalid for usage in the handshake.
+// Returns an error if there are no delegated credentials or if the one found
+// cannot be used for the current connection.
+func getDelegatedCredential(clientHello *ClientHelloInfo, cert *Certificate) (*DelegatedCredentialPair, error) {
+	if len(cert.DelegatedCredentials) == 0 {
+		return nil, errors.New("no Delegated Credential found")
+	}
+
+	for _, dcPair := range cert.DelegatedCredentials {
+		// The client must have sent the signature_algorithms in the DC extension: ensure it supports
+		// schemes we can use with this delegated credential.
+		if len(clientHello.SignatureSchemesDC) > 0 {
+			if _, err := selectSignatureSchemeDC(VersionTLS13, dcPair.DC, clientHello.SignatureSchemes, clientHello.SignatureSchemesDC); err == nil {
+				return &dcPair, nil
+			}
+		}
+	}
+
+	// No delegated credential can be returned.
+	return nil, errors.New("no valid Delegated Credential found")
+}
+
+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(clientHelloInfo(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
+
+	if hs.clientHello.delegatedCredentialSupported && len(hs.clientHello.supportedSignatureAlgorithmsDC) > 0 {
+		// getDelegatedCredential selects a delegated credential that the client has advertised support for, if possible.
+		delegatedCredentialPair, err := getDelegatedCredential(clientHelloInfo(hs.ctx, c, hs.clientHello), hs.cert)
+		if err != nil {
+			// a Delegated Credential was not found. Fallback to the certificate.
+			return nil
+		}
+		if delegatedCredentialPair.DC != nil && delegatedCredentialPair.PrivateKey != nil {
+			// Even if the Delegated Credential has already been marshalled, be sure it is the correct one.
+			delegatedCredentialPair.DC.raw, err = delegatedCredentialPair.DC.Marshal()
+			if err != nil {
+				// invalid Delegated Credential. Fallback to the certificate.
+				return nil
+			}
+			hs.sigAlg = delegatedCredentialPair.DC.cred.expCertVerfAlgo
+
+			hs.cert.PrivateKey = delegatedCredentialPair.PrivateKey
+			hs.cert.DelegatedCredential = delegatedCredentialPair.DC.raw
+		}
+	}
+	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
+
+	_, err := hs.c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	return err
+}
+
+func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error {
+	c := hs.c
+
+	c.handleCFEvent(CFEventTLS13HRR{})
+
+	// The first ClientHello gets double-hashed into the transcript upon a
+	// HelloRetryRequest. See RFC 8446, Section 4.4.1.
+	hs.transcript.Write(hs.clientHello.marshal())
+	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,
+	}
+
+	// Decide whether to send "encrypted_client_hello" extension.
+	if hs.echIsInner() {
+		// Confirm ECH acceptance if this is the inner handshake.
+		echAcceptConfHRRTranscript := cloneHash(hs.transcript, hs.suite.hash)
+		if echAcceptConfHRRTranscript == nil {
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: internal error: failed to clone hash")
+		}
+
+		helloRetryRequest.ech = zeros[:8]
+		echAcceptConfHRR := helloRetryRequest.marshal()
+		echAcceptConfHRRTranscript.Write(echAcceptConfHRR)
+		echAcceptConfHRRSignal := hs.suite.expandLabel(
+			hs.suite.extract(hs.clientHello.random, nil),
+			echAcceptConfHRRLabel,
+			echAcceptConfHRRTranscript.Sum(nil),
+			8)
+
+		helloRetryRequest.ech = echAcceptConfHRRSignal
+		helloRetryRequest.raw = nil
+	} else if c.ech.greased {
+		// draft-ietf-tls-esni-13, Section 7.1:
+		//
+		// If sending a HelloRetryRequest, the server MAY include an
+		// "encrypted_client_hello" extension with a payload of 8 random bytes;
+		// see Section 10.9.4 for details.
+		helloRetryRequest.ech = make([]byte, 8)
+		if _, err := io.ReadFull(c.config.rand(), helloRetryRequest.ech); err != nil {
+			c.sendAlert(alertInternalError)
+			return fmt.Errorf("tls: internal error: rng failure: %s", err)
+		}
+	}
+
+	hs.transcript.Write(helloRetryRequest.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal()); err != nil {
+		return err
+	}
+
+	if err := hs.sendDummyChangeCipherSpec(); err != nil {
+		return err
+	}
+
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	clientHello, ok := msg.(*clientHelloMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(clientHello, msg)
+	}
+
+	clientHello, err = c.echAcceptOrReject(clientHello, true) // afterHRR == true
+	if err != nil {
+		return fmt.Errorf("tls: %s", err) // Alert sent
+	}
+
+	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")
+	}
+
+	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.supportedSignatureAlgorithmsDC) != len(ch1.supportedSignatureAlgorithmsDC) ||
+		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.supportedSignatureAlgorithmsDC {
+		if ch.supportedSignatureAlgorithmsDC[i] != ch1.supportedSignatureAlgorithmsDC[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.delegatedCredentialSupported != ch1.delegatedCredentialSupported ||
+		ch.scts != ch1.scts ||
+		!bytes.Equal(ch.cookie, ch1.cookie) ||
+		!bytes.Equal(ch.pskModes, ch1.pskModes)
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
+	c := hs.c
+
+	// Confirm ECH acceptance.
+	if hs.echIsInner() {
+		// Clear the last 8 bytes of the ServerHello.random in preparation for
+		// computing the confirmation hint.
+		copy(hs.hello.random[24:], zeros[:8])
+
+		// Set the last 8 bytes of ServerHello.random to a string derived from
+		// the inner handshake.
+		echAcceptConfTranscript := cloneHash(hs.transcript, hs.suite.hash)
+		if echAcceptConfTranscript == nil {
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: internal error: failed to clone hash")
+		}
+		echAcceptConfTranscript.Write(hs.clientHello.marshal())
+		echAcceptConfTranscript.Write(hs.hello.marshal())
+
+		echAcceptConf := hs.suite.expandLabel(
+			hs.suite.extract(hs.clientHello.random, nil),
+			echAcceptConfLabel,
+			echAcceptConfTranscript.Sum(nil),
+			8)
+
+		copy(hs.hello.random[24:], echAcceptConf)
+		hs.hello.raw = nil
+	}
+
+	hs.transcript.Write(hs.clientHello.marshal())
+	hs.transcript.Write(hs.hello.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+		return err
+	}
+
+	hs.hsTimings.WriteServerHello = hs.hsTimings.elapsedTime()
+
+	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.setTrafficSecret(hs.suite, clientSecret)
+	serverSecret := hs.suite.deriveSecret(hs.handshakeSecret,
+		serverHandshakeTrafficLabel, hs.transcript)
+	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
+	}
+
+	encryptedExtensions := new(encryptedExtensionsMsg)
+
+	selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
+	if err != nil {
+		c.sendAlert(alertNoApplicationProtocol)
+		return err
+	}
+	encryptedExtensions.alpnProtocol = selectedProto
+	c.clientProtocol = selectedProto
+
+	if !c.ech.accepted && len(c.ech.retryConfigs) > 0 {
+		encryptedExtensions.ech = c.ech.retryConfigs
+	}
+
+	hs.transcript.Write(encryptedExtensions.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()); err != nil {
+		return err
+	}
+
+	hs.hsTimings.WriteEncryptedExtensions = hs.hsTimings.elapsedTime()
+
+	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 = c.config.supportedSignatureAlgorithms()
+		certReq.supportDelegatedCredential = c.config.SupportDelegatedCredential
+		certReq.supportedSignatureAlgorithmsDC = supportedSignatureAlgorithmsDC
+		if c.config.ClientCAs != nil {
+			certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
+		}
+
+		hs.certReq = certReq
+		hs.transcript.Write(certReq.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); 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
+	certMsg.delegatedCredential = hs.clientHello.delegatedCredentialSupported && len(hs.cert.DelegatedCredential) > 0
+
+	hs.transcript.Write(certMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+		return err
+	}
+
+	hs.hsTimings.WriteCertificate = hs.hsTimings.elapsedTime()
+
+	certVerifyMsg := new(certificateVerifyMsg)
+	certVerifyMsg.hasSignatureAlgorithm = true
+	certVerifyMsg.signatureAlgorithm = hs.sigAlg
+	sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
+	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
+
+	hs.transcript.Write(certVerifyMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, certVerifyMsg.marshal()); err != nil {
+		return err
+	}
+
+	hs.hsTimings.WriteCertificateVerify = hs.hsTimings.elapsedTime()
+
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
+	c := hs.c
+
+	finished := &finishedMsg{
+		verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
+	}
+
+	hs.transcript.Write(finished.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+		return err
+	}
+
+	hs.hsTimings.WriteServerFinished = hs.hsTimings.elapsedTime()
+
+	// 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.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 || hs.c.config.ECHEnabled {
+		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,
+	}
+	hs.transcript.Write(finishedMsg.marshal())
+
+	if !hs.shouldSendSessionTickets() {
+		return nil
+	}
+
+	resumptionSecret := hs.suite.deriveSecret(hs.masterSecret,
+		resumptionLabel, hs.transcript)
+
+	m := new(newSessionTicketMsgTLS13)
+
+	var certsFromClient [][]byte
+	for _, cert := range c.peerCertificates {
+		certsFromClient = append(certsFromClient, cert.Raw)
+	}
+	state := sessionStateTLS13{
+		cipherSuite:      hs.suite.id,
+		createdAt:        uint64(c.config.time().Unix()),
+		resumptionSecret: resumptionSecret,
+		certificate: Certificate{
+			Certificate:                 certsFromClient,
+			OCSPStaple:                  c.ocspResponse,
+			SignedCertificateTimestamps: c.scts,
+		},
+	}
+	var err error
+	m.label, err = c.encryptTicket(state.marshal())
+	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 = hs.c.config.rand().Read(ageAdd)
+	if err != nil {
+		return 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 _, err := c.writeRecord(recordTypeHandshake, m.marshal()); 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()
+	if err != nil {
+		return err
+	}
+
+	certMsg, ok := msg.(*certificateMsgTLS13)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certMsg, msg)
+	}
+	hs.transcript.Write(certMsg.marshal())
+
+	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
+		}
+	}
+
+	hs.hsTimings.ReadCertificate = hs.hsTimings.elapsedTime()
+
+	if len(certMsg.certificate.Certificate) != 0 {
+		msg, err = c.readHandshake()
+		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, c.config.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")
+		}
+
+		if certMsg.delegatedCredential {
+			if err := hs.processDelegatedCredentialFromClient(certMsg.certificate.DelegatedCredential, certVerify); err != nil {
+				return err
+			}
+		}
+
+		pk := c.peerCertificates[0].PublicKey
+		if c.verifiedDC != nil {
+			pk = c.verifiedDC.cred.publicKey
+		}
+
+		signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
+		if err := verifyHandshakeSignature(sigType, pk, sigHash, signed, certVerify.signature); err != nil {
+			c.sendAlert(alertDecryptError)
+			return errors.New("tls: invalid signature by the client certificate: " + err.Error())
+		}
+
+		hs.transcript.Write(certVerify.marshal())
+	}
+
+	hs.hsTimings.ReadCertificateVerify = hs.hsTimings.elapsedTime()
+
+	// 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
+
+	msg, err := c.readHandshake()
+	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")
+	}
+
+	hs.hsTimings.ReadClientFinished = hs.hsTimings.elapsedTime()
+
+	c.in.setTrafficSecret(hs.suite, hs.trafficSecret)
+
+	return nil
+}

+ 42 - 0
transport/cloudflaretls/hpke.go

@@ -0,0 +1,42 @@
+// Copyright 2020 Cloudflare, Inc. All rights reserved. Use of this source code
+// is governed by a BSD-style license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/cloudflare/circl/hpke"
+)
+
+// The mandatory-to-implement HPKE cipher suite for use with the ECH extension.
+var defaultHPKESuite hpke.Suite
+
+func init() {
+	var err error
+	defaultHPKESuite, err = hpkeAssembleSuite(
+		uint16(hpke.KEM_X25519_HKDF_SHA256),
+		uint16(hpke.KDF_HKDF_SHA256),
+		uint16(hpke.AEAD_AES128GCM),
+	)
+	if err != nil {
+		panic(fmt.Sprintf("hpke: mandatory-to-implement cipher suite not supported: %s", err))
+	}
+}
+
+func hpkeAssembleSuite(kemId, kdfId, aeadId uint16) (hpke.Suite, error) {
+	kem := hpke.KEM(kemId)
+	if !kem.IsValid() {
+		return hpke.Suite{}, errors.New("KEM is not supported")
+	}
+	kdf := hpke.KDF(kdfId)
+	if !kdf.IsValid() {
+		return hpke.Suite{}, errors.New("KDF is not supported")
+	}
+	aead := hpke.AEAD(aeadId)
+	if !aead.IsValid() {
+		return hpke.Suite{}, errors.New("AEAD is not supported")
+	}
+	return hpke.NewSuite(kem, kdf, aead), nil
+}

+ 359 - 0
transport/cloudflaretls/key_agreement.go

@@ -0,0 +1,359 @@
+// 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 tls
+
+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")
+	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 || circlSchemeBySigType(sigType) != nil {
+		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) && curveIdToCirclScheme(c) == nil {
+			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
+}

+ 199 - 0
transport/cloudflaretls/key_schedule.go

@@ -0,0 +1,199 @@
+// 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 tls
+
+import (
+	"crypto/elliptic"
+	"crypto/hmac"
+	"errors"
+	"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)
+	})
+	out := make([]byte, length)
+	n, err := hkdf.Expand(c.hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out)
+	if err != nil || n != length {
+		panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
+	}
+	return out
+}
+
+// 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
+}

+ 285 - 0
transport/cloudflaretls/prf.go

@@ -0,0 +1,285 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"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")
+	keyExpansionLabel   = []byte("key expansion")
+	clientFinishedLabel = []byte("client finished")
+	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 || circlSchemeBySigType(sigType) != nil) && h.buffer == nil {
+		panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer")
+	}
+
+	if sigType == signatureEd25519 || circlSchemeBySigType(sigType) != nil {
+		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
+	}
+}

+ 185 - 0
transport/cloudflaretls/ticket.go

@@ -0,0 +1,185 @@
+// 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 tls
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/sha256"
+	"crypto/subtle"
+	"errors"
+	"io"
+
+	"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 {
+	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.BytesOrPanic()
+}
+
+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.
+type sessionStateTLS13 struct {
+	// uint8 version  = 0x0304;
+	// uint8 revision = 0;
+	cipherSuite      uint16
+	createdAt        uint64
+	resumptionSecret []byte      // opaque resumption_master_secret<1..2^8-1>;
+	certificate      Certificate // CertificateEntry certificate_list<0..2^24-1>;
+}
+
+func (m *sessionStateTLS13) marshal() []byte {
+	var b cryptobyte.Builder
+	b.AddUint16(VersionTLS13)
+	b.AddUint8(0) // revision
+	b.AddUint16(m.cipherSuite)
+	addUint64(&b, m.createdAt)
+	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(m.resumptionSecret)
+	})
+	marshalCertificate(&b, m.certificate)
+	return b.BytesOrPanic()
+}
+
+func (m *sessionStateTLS13) unmarshal(data []byte) bool {
+	*m = sessionStateTLS13{}
+	s := cryptobyte.String(data)
+	var version uint16
+	var revision uint8
+	return s.ReadUint16(&version) &&
+		version == VersionTLS13 &&
+		s.ReadUint8(&revision) &&
+		revision == 0 &&
+		s.ReadUint16(&m.cipherSuite) &&
+		readUint64(&s, &m.createdAt) &&
+		readUint8LengthPrefixed(&s, &m.resumptionSecret) &&
+		len(m.resumptionSecret) != 0 &&
+		unmarshalCertificate(&s, &m.certificate) &&
+		s.Empty()
+}
+
+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
+}

+ 410 - 0
transport/cloudflaretls/tls.go

@@ -0,0 +1,410 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tls partially implements TLS 1.2, as specified in RFC 5246,
+// and TLS 1.3, as specified in RFC 8446.
+//
+// This package implements the "Encrypted ClientHello (ECH)" extension, as
+// specified by draft-ietf-tls-esni-13. This extension allows the client to
+// encrypt its ClientHello to the public key of an ECH-service provider, known
+// as the client-facing server. If successful, then the client-facing server
+// forwards the decrypted ClientHello to the intended recipient, known as the
+// backend server. The goal of this mechanism is to ensure that connections made
+// to backend servers are indistinguishable from one another.
+//
+// This package implements the "Delegated Credentials" extension, as
+// specified by draft-ietf-tls-subcerts-10. This extension allows the usage
+// of a limited delegation mechanism that allows a TLS peer to issue its own
+// credentials within the scope of a certificate issued by an external
+// CA. These credentials only enable the recipient of the delegation to
+// speak for names that the CA has authorized. If the client or server supports
+// this extension, then the server or client may use a "delegated credential"
+// as the signing key in the handshake. A delegated credential is a short lived
+// public/secret key pair delegated to the peer by an entity trusted by the
+// corresponding peer. This allows a reverse proxy to terminate a TLS connection
+// on behalf of the entity. Credentials can't be revoked; in order to
+// mitigate risk in case the reverse proxy is compromised, the credential is only
+// valid for a short time (days, hours, or even minutes).
+package tls
+
+// BUG(cjpatton): In order to achieve its security goal, the ECH extension
+// requires padding in order to ensure that the length of handshake messages
+// doesn't depend on who terminates the connection. This package does not yet
+// implement server-side padding: see
+// https://github.com/tlswg/draft-ietf-tls-esni/issues/264.
+
+// BUG(cjpatton): The interaction of the ECH extension with PSK has not yet been
+// fully vetted. For now, the server disables session tickets if ECH is enabled.
+
+// BUG(cjpatton): Upon ECH rejection, if retry configurations are provided, then
+// the client is expected to retry the connection. Otherwise, it may regard ECH
+// as being securely disabled by the client-facing server. The client in this
+// package does not attempt to retry the handshake.
+
+// BUG(cjpatton): If the client offers the ECH extension and the client-facing
+// server rejects it, then only the client-facing server is authenticated. In
+// particular, the client is expected to respond to a CertificateRequest with an
+// empty certificate. This package does not yet implement this behavior.
+
+// 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"
+
+	circlSign "github.com/cloudflare/circl/sign"
+)
+
+// 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) *Conn {
+	c := &Conn{
+		conn:   conn,
+		config: config,
+	}
+	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) *Conn {
+	c := &Conn{
+		conn:     conn,
+		config:   config,
+		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
+}
+
+// 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), 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) net.Listener {
+	l := new(listener)
+	l.Listener = inner
+	l.config = config
+	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) (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), 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) (*Conn, error) {
+	return dial(context.Background(), dialer, network, addr, config)
+}
+
+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)
+		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)
+	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) (*Conn, error) {
+	return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
+// 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
+}
+
+// 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)
+	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"))
+		}
+	case circlSign.PublicKey:
+		priv, ok := cert.PrivateKey.(circlSign.PrivateKey)
+		if !ok {
+			return fail(errors.New("tls: private key type does not match public key type"))
+		}
+		pkBytes, err := priv.Public().(circlSign.PublicKey).MarshalBinary()
+		pkBytes2, err2 := pub.MarshalBinary()
+
+		if err != nil || err2 != nil || !bytes.Equal(pkBytes, pkBytes2) {
+			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, circlSign.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")
+}

+ 241 - 0
transport/cloudflaretls/tls_cf.go

@@ -0,0 +1,241 @@
+// Copyright 2021 Cloudflare, Inc. All rights reserved. Use of this source code
+// is governed by a BSD-style license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"time"
+
+	circlPki "github.com/cloudflare/circl/pki"
+	circlSign "github.com/cloudflare/circl/sign"
+	"github.com/cloudflare/circl/sign/eddilithium3"
+)
+
+const (
+	// Constants for ECH status events.
+	echStatusBypassed = 1 + iota
+	echStatusInner
+	echStatusOuter
+)
+
+// To add a signature scheme from Circl
+//
+//   1. make sure it implements TLSScheme and CertificateScheme,
+//   2. follow the instructions in crypto/x509/x509_cf.go
+//   3. add a signature<NameOfAlg> to the iota in common.go
+//   4. add row in the circlSchemes lists below
+
+var circlSchemes = [...]struct {
+	sigType uint8
+	scheme  circlSign.Scheme
+}{
+	{signatureEdDilithium3, eddilithium3.Scheme()},
+}
+
+func circlSchemeBySigType(sigType uint8) circlSign.Scheme {
+	for _, cs := range circlSchemes {
+		if cs.sigType == sigType {
+			return cs.scheme
+		}
+	}
+	return nil
+}
+
+func sigTypeByCirclScheme(scheme circlSign.Scheme) uint8 {
+	for _, cs := range circlSchemes {
+		if cs.scheme == scheme {
+			return cs.sigType
+		}
+	}
+	return 0
+}
+
+var supportedSignatureAlgorithmsWithCircl []SignatureScheme
+
+// supportedSignatureAlgorithms returns enabled signature schemes. PQ signature
+// schemes are only included when tls.Config#PQSignatureSchemesEnabled is set.
+func (c *Config) supportedSignatureAlgorithms() []SignatureScheme {
+	if c != nil && c.PQSignatureSchemesEnabled {
+		return supportedSignatureAlgorithmsWithCircl
+	}
+	return supportedSignatureAlgorithms
+}
+
+func init() {
+	supportedSignatureAlgorithmsWithCircl = append([]SignatureScheme{}, supportedSignatureAlgorithms...)
+	for _, cs := range circlSchemes {
+		supportedSignatureAlgorithmsWithCircl = append(supportedSignatureAlgorithmsWithCircl,
+			SignatureScheme(cs.scheme.(circlPki.TLSScheme).TLSIdentifier()))
+	}
+}
+
+// CFEvent is a value emitted at various points in the handshake that is
+// handled by the callback Config.CFEventHandler.
+type CFEvent interface {
+	Name() string
+}
+
+// CFEventTLS13ClientHandshakeTimingInfo carries intra-stack time durations for
+// TLS 1.3 client-state machine changes. It can be used for tracking metrics
+// during a connection. Some durations may be sensitive, such as the amount of
+// time to process a particular handshake message, so this event should only be
+// used for experimental purposes.
+type CFEventTLS13ClientHandshakeTimingInfo struct {
+	timer                   func() time.Time
+	start                   time.Time
+	WriteClientHello        time.Duration
+	ProcessServerHello      time.Duration
+	ReadEncryptedExtensions time.Duration
+	ReadCertificate         time.Duration
+	ReadCertificateVerify   time.Duration
+	ReadServerFinished      time.Duration
+	WriteCertificate        time.Duration
+	WriteCertificateVerify  time.Duration
+	WriteClientFinished     time.Duration
+}
+
+// Name is required by the CFEvent interface.
+func (e CFEventTLS13ClientHandshakeTimingInfo) Name() string {
+	return "TLS13ClientHandshakeTimingInfo"
+}
+
+func (e CFEventTLS13ClientHandshakeTimingInfo) elapsedTime() time.Duration {
+	if e.timer == nil {
+		return 0
+	}
+	return e.timer().Sub(e.start)
+}
+
+func createTLS13ClientHandshakeTimingInfo(timerFunc func() time.Time) CFEventTLS13ClientHandshakeTimingInfo {
+	timer := time.Now
+	if timerFunc != nil {
+		timer = timerFunc
+	}
+
+	return CFEventTLS13ClientHandshakeTimingInfo{
+		timer: timer,
+		start: timer(),
+	}
+}
+
+// CFEventTLS13ServerHandshakeTimingInfo carries intra-stack time durations
+// for TLS 1.3 state machine changes. It can be used for tracking metrics during a
+// connection. Some durations may be sensitive, such as the amount of time to
+// process a particular handshake message, so this event should only be used
+// for experimental purposes.
+type CFEventTLS13ServerHandshakeTimingInfo struct {
+	timer                    func() time.Time
+	start                    time.Time
+	ProcessClientHello       time.Duration
+	WriteServerHello         time.Duration
+	WriteEncryptedExtensions time.Duration
+	WriteCertificate         time.Duration
+	WriteCertificateVerify   time.Duration
+	WriteServerFinished      time.Duration
+	ReadCertificate          time.Duration
+	ReadCertificateVerify    time.Duration
+	ReadClientFinished       time.Duration
+}
+
+// Name is required by the CFEvent interface.
+func (e CFEventTLS13ServerHandshakeTimingInfo) Name() string {
+	return "TLS13ServerHandshakeTimingInfo"
+}
+
+func (e CFEventTLS13ServerHandshakeTimingInfo) elapsedTime() time.Duration {
+	if e.timer == nil {
+		return 0
+	}
+	return e.timer().Sub(e.start)
+}
+
+func createTLS13ServerHandshakeTimingInfo(timerFunc func() time.Time) CFEventTLS13ServerHandshakeTimingInfo {
+	timer := time.Now
+	if timerFunc != nil {
+		timer = timerFunc
+	}
+
+	return CFEventTLS13ServerHandshakeTimingInfo{
+		timer: timer,
+		start: timer(),
+	}
+}
+
+// CFEventECHClientStatus is emitted once it is known whether the client
+// bypassed, offered, or greased ECH.
+type CFEventECHClientStatus int
+
+// Bypassed returns true if the client bypassed ECH.
+func (e CFEventECHClientStatus) Bypassed() bool {
+	return e == echStatusBypassed
+}
+
+// Offered returns true if the client offered ECH.
+func (e CFEventECHClientStatus) Offered() bool {
+	return e == echStatusInner
+}
+
+// Greased returns true if the client greased ECH.
+func (e CFEventECHClientStatus) Greased() bool {
+	return e == echStatusOuter
+}
+
+// Name is required by the CFEvent interface.
+func (e CFEventECHClientStatus) Name() string {
+	return "ech client status"
+}
+
+// CFEventECHServerStatus is emitted once it is known whether the client
+// bypassed, offered, or greased ECH.
+type CFEventECHServerStatus int
+
+// Bypassed returns true if the client bypassed ECH.
+func (e CFEventECHServerStatus) Bypassed() bool {
+	return e == echStatusBypassed
+}
+
+// Accepted returns true if the client offered ECH.
+func (e CFEventECHServerStatus) Accepted() bool {
+	return e == echStatusInner
+}
+
+// Rejected returns true if the client greased ECH.
+func (e CFEventECHServerStatus) Rejected() bool {
+	return e == echStatusOuter
+}
+
+// Name is required by the CFEvent interface.
+func (e CFEventECHServerStatus) Name() string {
+	return "ech server status"
+}
+
+// CFEventECHPublicNameMismatch is emitted if the outer SNI does not match
+// match the public name of the ECH configuration. Note that we do not record
+// the outer SNI in order to avoid collecting this potentially sensitive data.
+type CFEventECHPublicNameMismatch struct{}
+
+// Name is required by the CFEvent interface.
+func (e CFEventECHPublicNameMismatch) Name() string {
+	return "ech public name does not match outer sni"
+}
+
+// For backwards compatibility.
+type CFEventTLS13NegotiatedKEX = CFEventTLSNegotiatedNamedKEX
+
+// CFEventTLSNegotiatedNamedKEX is emitted when a key agreement mechanism has been
+// established that uses a named group. This includes all key agreements
+// in TLSv1.3, but excludes RSA and DH in TLS 1.2 and earlier.
+type CFEventTLSNegotiatedNamedKEX struct {
+	KEX CurveID
+}
+
+func (e CFEventTLSNegotiatedNamedKEX) Name() string {
+	return "CFEventTLSNegotiatedNamedKEX"
+}
+
+// CFEventTLS13HRR is emitted when a HRR is sent or received
+type CFEventTLS13HRR struct{}
+
+func (e CFEventTLS13HRR) Name() string {
+	return "CFEventTLS13HRR"
+}