Просмотр исходного кода

Added go1.21 support

* Using psiphon-tls fork of crypto/tls
* Updated quic-go to v0.40.1
Amir Khan 2 лет назад
Родитель
Сommit
04f5a0dff4
32 измененных файлов с 12918 добавлено и 34 удалено
  1. 2 1
      go.mod
  2. 4 2
      go.sum
  3. 15 8
      psiphon/common/quic/quic.go
  4. 21 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/.gitignore
  5. 32 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/LICENSE
  6. 109 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/alert.go
  7. 293 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/auth.go
  8. 102 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/boring.go
  9. 95 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/cache.go
  10. 684 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/cipher_suites.go
  11. 1499 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/common.go
  12. 1676 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/conn.go
  13. 1150 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_client.go
  14. 768 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_client_tls13.go
  15. 2267 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_messages.go
  16. 955 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_server.go
  17. 991 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_server_tls13.go
  18. 366 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/key_agreement.go
  19. 159 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/key_schedule.go
  20. 22 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/notboring.go
  21. 292 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/prf.go
  22. 427 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/quic.go
  23. 426 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/ticket.go
  24. 356 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/tls.go
  25. 140 0
      vendor/github.com/Psiphon-Labs/psiphon-tls/unsafe.go
  26. 31 6
      vendor/github.com/Psiphon-Labs/quic-go/framer.go
  27. 9 5
      vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/crypto_setup.go
  28. 6 5
      vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/cipher_suite_go121.go
  29. 2 4
      vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go120.go
  30. 8 1
      vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go121.go
  31. 7 1
      vendor/github.com/Psiphon-Labs/quic-go/packet_packer.go
  32. 4 1
      vendor/modules.txt

+ 2 - 1
go.mod

@@ -10,7 +10,7 @@ require (
 	github.com/Psiphon-Inc/rotate-safe-writer v0.0.0-20210303140923-464a7a37606e
 	github.com/Psiphon-Labs/bolt v0.0.0-20200624191537-23cedaef7ad7
 	github.com/Psiphon-Labs/goptlib v0.0.0-20200406165125-c0e32a7a3464
-	github.com/Psiphon-Labs/quic-go v0.0.0-20231117205605-756d3e334a3b
+	github.com/Psiphon-Labs/quic-go v0.0.0-20240130155801-3197a7943511
 	github.com/Psiphon-Labs/tls-tris v0.0.0-20230824155421-58bf6d336a9a
 	github.com/armon/go-proxyproto v0.0.0-20180202201750-5b7edb60ff5f
 	github.com/bifurcation/mint v0.0.0-20180306135233-198357931e61
@@ -53,6 +53,7 @@ require (
 	filippo.io/keygen v0.0.0-20230306160926-5201437acf8e // indirect
 	github.com/AndreasBriese/bbloom v0.0.0-20170702084017-28f7e881ca57 // indirect
 	github.com/BurntSushi/toml v1.3.2 // indirect
+	github.com/Psiphon-Labs/psiphon-tls v0.0.0-20240129160049-e465a08acc16 // indirect
 	github.com/Psiphon-Labs/qtls-go1-20 v0.0.0-20231117202359-5544003bda6f // indirect
 	github.com/andybalholm/brotli v1.0.5 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect

+ 4 - 2
go.sum

@@ -13,10 +13,12 @@ github.com/Psiphon-Labs/bolt v0.0.0-20200624191537-23cedaef7ad7 h1:Hx/NCZTnvoKZu
 github.com/Psiphon-Labs/bolt v0.0.0-20200624191537-23cedaef7ad7/go.mod h1:alTtZBo3j4AWFvUrAH6F5ZaHcTj4G5Y01nHz8dkU6vU=
 github.com/Psiphon-Labs/goptlib v0.0.0-20200406165125-c0e32a7a3464 h1:VmnMMMheFXwLV0noxYhbJbLmkV4iaVW3xNnj6xcCNHo=
 github.com/Psiphon-Labs/goptlib v0.0.0-20200406165125-c0e32a7a3464/go.mod h1:Pe5BqN2DdIdChorAXl6bDaQd/wghpCleJfid2NoSli0=
+github.com/Psiphon-Labs/psiphon-tls v0.0.0-20240129160049-e465a08acc16 h1:/uzNbDLPVhmeTieLzcTVYQ9W2m88wcg5Zp3e1rwUfLg=
+github.com/Psiphon-Labs/psiphon-tls v0.0.0-20240129160049-e465a08acc16/go.mod h1:MzvOK7DlXAkfZ7wrgwQmBoBsbo22c9qaz2JYlEXwoTk=
 github.com/Psiphon-Labs/qtls-go1-20 v0.0.0-20231117202359-5544003bda6f h1:x33cklt4AZ9K8a9EpmFLjIxjZwPXeWWb124OYstlTmA=
 github.com/Psiphon-Labs/qtls-go1-20 v0.0.0-20231117202359-5544003bda6f/go.mod h1:f6akxitY5DYvGtbI+LkDSvw0bctE75P63bX6nb0V+eg=
-github.com/Psiphon-Labs/quic-go v0.0.0-20231117205605-756d3e334a3b h1:5pmQY2Fqucs10whrTUFhTO/7xl4uysLV2+OvfmQoBpU=
-github.com/Psiphon-Labs/quic-go v0.0.0-20231117205605-756d3e334a3b/go.mod h1:Wb77BjnG/Khoag8bfLRnFA4TyT8C9+xAwcmVGGB3Ob0=
+github.com/Psiphon-Labs/quic-go v0.0.0-20240130155801-3197a7943511 h1:G9W0L5vPAUTe3q6WsfiPHWyOR77IPF1WQczrbcpFuvU=
+github.com/Psiphon-Labs/quic-go v0.0.0-20240130155801-3197a7943511/go.mod h1:r1tG/07t55w+vAQ+y4uYSNLWlkXAPYNknfLw/ketvOQ=
 github.com/Psiphon-Labs/tls-tris v0.0.0-20230824155421-58bf6d336a9a h1:BOfU6ghaMsT/c40sWHmf3PXNwIendYXzL6tRv6NbPog=
 github.com/Psiphon-Labs/tls-tris v0.0.0-20230824155421-58bf6d336a9a/go.mod h1:v3y9GXFo9Sf2mO6auD2ExGG7oDgrK8TI7eb49ZnUxrE=
 github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=

+ 15 - 8
psiphon/common/quic/quic.go

@@ -254,7 +254,10 @@ func Listen(
 			return nil, errors.Trace(err)
 		}
 
-		quicListener = &ietfQUICListener{Listener: listener}
+		quicListener = &ietfQUICListener{
+			Listener:  listener,
+			transport: tr,
+		}
 
 	} else {
 
@@ -343,12 +346,6 @@ func (listener *Listener) Accept() (net.Conn, error) {
 }
 
 func (listener *Listener) Close() error {
-
-	// First close the underlying packet conn to ensure all quic-go goroutines
-	// as well as any blocking Accept call goroutine is interrupted. Note
-	// that muxListener does this as well, so this is for the IETF-only case.
-	_ = listener.obfuscatedPacketConn.Close()
-
 	return listener.quicListener.Close()
 }
 
@@ -907,6 +904,7 @@ type quicRoundTripper interface {
 
 type ietfQUICListener struct {
 	*ietf_quic.Listener
+	transport *ietf_quic.Transport
 }
 
 func (l *ietfQUICListener) Accept() (quicConnection, error) {
@@ -919,6 +917,12 @@ func (l *ietfQUICListener) Accept() (quicConnection, error) {
 	return &ietfQUICConnection{Connection: connection}, nil
 }
 
+func (l *ietfQUICListener) Close() error {
+	// All quic-go goroutines will be stopped when the transport is closed.
+	// https://github.com/quic-go/quic-go/issues/3962
+	return l.transport.Close()
+}
+
 type ietfQUICConnection struct {
 	ietf_quic.Connection
 }
@@ -1198,7 +1202,10 @@ func newMuxListener(
 	if err != nil {
 		return nil, errors.Trace(err)
 	}
-	listener.ietfQUICListener = &ietfQUICListener{Listener: il}
+	listener.ietfQUICListener = &ietfQUICListener{
+		Listener:  il,
+		transport: tr,
+	}
 
 	listener.gQUICConn = newMuxPacketConn(conn.LocalAddr(), listener)
 

+ 21 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/.gitignore

@@ -0,0 +1,21 @@
+# If you prefer the allow list template instead of the deny list, see community template:
+# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
+#
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
+
+# Go workspace file
+go.work

+ 32 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/LICENSE

@@ -0,0 +1,32 @@
+Psiphon modifications:
+Copyright (c) 2024, Psiphon Inc. All rights reserved.
+
+Original cryoto/tls:
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+

+ 109 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/alert.go

@@ -0,0 +1,109 @@
+// 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"
+
+// An AlertError is a TLS alert.
+//
+// When using a QUIC transport, QUICConn methods will return an error
+// which wraps AlertError rather than sending a TLS alert.
+type AlertError uint8
+
+func (e AlertError) Error() string {
+	return alert(e).String()
+}
+
+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
+)
+
+var alertText = map[alert]string{
+	alertCloseNotify:                  "close notify",
+	alertUnexpectedMessage:            "unexpected message",
+	alertBadRecordMAC:                 "bad record MAC",
+	alertDecryptionFailed:             "decryption failed",
+	alertRecordOverflow:               "record overflow",
+	alertDecompressionFailure:         "decompression failure",
+	alertHandshakeFailure:             "handshake failure",
+	alertBadCertificate:               "bad certificate",
+	alertUnsupportedCertificate:       "unsupported certificate",
+	alertCertificateRevoked:           "revoked certificate",
+	alertCertificateExpired:           "expired certificate",
+	alertCertificateUnknown:           "unknown certificate",
+	alertIllegalParameter:             "illegal parameter",
+	alertUnknownCA:                    "unknown certificate authority",
+	alertAccessDenied:                 "access denied",
+	alertDecodeError:                  "error decoding message",
+	alertDecryptError:                 "error decrypting message",
+	alertExportRestriction:            "export restriction",
+	alertProtocolVersion:              "protocol version not supported",
+	alertInsufficientSecurity:         "insufficient security level",
+	alertInternalError:                "internal error",
+	alertInappropriateFallback:        "inappropriate fallback",
+	alertUserCanceled:                 "user canceled",
+	alertNoRenegotiation:              "no renegotiation",
+	alertMissingExtension:             "missing extension",
+	alertUnsupportedExtension:         "unsupported extension",
+	alertCertificateUnobtainable:      "certificate unobtainable",
+	alertUnrecognizedName:             "unrecognized name",
+	alertBadCertificateStatusResponse: "bad certificate status response",
+	alertBadCertificateHashValue:      "bad certificate hash value",
+	alertUnknownPSKIdentity:           "unknown PSK identity",
+	alertCertificateRequired:          "certificate required",
+	alertNoApplicationProtocol:        "no application protocol",
+}
+
+func (e alert) String() string {
+	s, ok := alertText[e]
+	if ok {
+		return "tls: " + s
+	}
+	return "tls: alert(" + strconv.Itoa(int(e)) + ")"
+}
+
+func (e alert) Error() string {
+	return e.String()
+}

+ 293 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/auth.go

@@ -0,0 +1,293 @@
+// 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"
+)
+
+// verifyHandshakeSignature verifies a signature against pre-hashed
+// (if required) handshake contents.
+func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error {
+	switch sigType {
+	case signatureECDSA:
+		pubKey, ok := pubkey.(*ecdsa.PublicKey)
+		if !ok {
+			return fmt.Errorf("expected an ECDSA public key, got %T", pubkey)
+		}
+		if !ecdsa.VerifyASN1(pubKey, signed, sig) {
+			return errors.New("ECDSA verification failure")
+		}
+	case signatureEd25519:
+		pubKey, ok := pubkey.(ed25519.PublicKey)
+		if !ok {
+			return fmt.Errorf("expected an Ed25519 public key, got %T", pubkey)
+		}
+		if !ed25519.Verify(pubKey, signed, sig) {
+			return errors.New("Ed25519 verification failure")
+		}
+	case signaturePKCS1v15:
+		pubKey, ok := pubkey.(*rsa.PublicKey)
+		if !ok {
+			return fmt.Errorf("expected an RSA public key, got %T", pubkey)
+		}
+		if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, signed, sig); err != nil {
+			return err
+		}
+	case signatureRSAPSS:
+		pubKey, ok := pubkey.(*rsa.PublicKey)
+		if !ok {
+			return fmt.Errorf("expected an RSA public key, got %T", pubkey)
+		}
+		signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}
+		if err := rsa.VerifyPSS(pubKey, hashFunc, signed, sig, signOpts); err != nil {
+			return err
+		}
+	default:
+		return errors.New("internal error: unknown signature type")
+	}
+	return nil
+}
+
+const (
+	serverSignatureContext = "TLS 1.3, server CertificateVerify\x00"
+	clientSignatureContext = "TLS 1.3, client CertificateVerify\x00"
+)
+
+var signaturePadding = []byte{
+	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+}
+
+// signedMessage returns the pre-hashed (if necessary) message to be signed by
+// certificate keys in TLS 1.3. See RFC 8446, Section 4.4.3.
+func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []byte {
+	if sigHash == directSigning {
+		b := &bytes.Buffer{}
+		b.Write(signaturePadding)
+		io.WriteString(b, context)
+		b.Write(transcript.Sum(nil))
+		return b.Bytes()
+	}
+	h := sigHash.New()
+	h.Write(signaturePadding)
+	io.WriteString(h, context)
+	h.Write(transcript.Sum(nil))
+	return h.Sum(nil)
+}
+
+// typeAndHashFromSignatureScheme returns the corresponding signature type and
+// crypto.Hash for a given TLS SignatureScheme.
+func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) {
+	switch signatureAlgorithm {
+	case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
+		sigType = signaturePKCS1v15
+	case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
+		sigType = signatureRSAPSS
+	case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
+		sigType = signatureECDSA
+	case Ed25519:
+		sigType = signatureEd25519
+	default:
+		return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
+	}
+	switch signatureAlgorithm {
+	case PKCS1WithSHA1, ECDSAWithSHA1:
+		hash = crypto.SHA1
+	case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
+		hash = crypto.SHA256
+	case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
+		hash = crypto.SHA384
+	case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
+		hash = crypto.SHA512
+	case Ed25519:
+		hash = directSigning
+	default:
+		return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
+	}
+	return sigType, hash, nil
+}
+
+// legacyTypeAndHashFromPublicKey returns the fixed signature type and crypto.Hash for
+// a given public key used with TLS 1.0 and 1.1, before the introduction of
+// signature algorithm negotiation.
+func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash crypto.Hash, err error) {
+	switch pub.(type) {
+	case *rsa.PublicKey:
+		return signaturePKCS1v15, crypto.MD5SHA1, nil
+	case *ecdsa.PublicKey:
+		return signatureECDSA, crypto.SHA1, nil
+	case ed25519.PublicKey:
+		// RFC 8422 specifies support for Ed25519 in TLS 1.0 and 1.1,
+		// but it requires holding on to a handshake transcript to do a
+		// full signature, and not even OpenSSL bothers with the
+		// complexity, so we can't even test it properly.
+		return 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2")
+	default:
+		return 0, 0, fmt.Errorf("tls: unsupported public key: %T", pub)
+	}
+}
+
+var rsaSignatureSchemes = []struct {
+	scheme          SignatureScheme
+	minModulusBytes int
+	maxVersion      uint16
+}{
+	// RSA-PSS is used with PSSSaltLengthEqualsHash, and requires
+	//    emLen >= hLen + sLen + 2
+	{PSSWithSHA256, crypto.SHA256.Size()*2 + 2, VersionTLS13},
+	{PSSWithSHA384, crypto.SHA384.Size()*2 + 2, VersionTLS13},
+	{PSSWithSHA512, crypto.SHA512.Size()*2 + 2, VersionTLS13},
+	// PKCS #1 v1.5 uses prefixes from hashPrefixes in crypto/rsa, and requires
+	//    emLen >= len(prefix) + hLen + 11
+	// TLS 1.3 dropped support for PKCS #1 v1.5 in favor of RSA-PSS.
+	{PKCS1WithSHA256, 19 + crypto.SHA256.Size() + 11, VersionTLS12},
+	{PKCS1WithSHA384, 19 + crypto.SHA384.Size() + 11, VersionTLS12},
+	{PKCS1WithSHA512, 19 + crypto.SHA512.Size() + 11, VersionTLS12},
+	{PKCS1WithSHA1, 15 + crypto.SHA1.Size() + 11, VersionTLS12},
+}
+
+// signatureSchemesForCertificate returns the list of supported SignatureSchemes
+// for a given certificate, based on the public key and the protocol version,
+// and optionally filtered by its explicit SupportedSignatureAlgorithms.
+//
+// This function must be kept in sync with supportedSignatureAlgorithms.
+// FIPS filtering is applied in the caller, selectSignatureScheme.
+func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
+	priv, ok := cert.PrivateKey.(crypto.Signer)
+	if !ok {
+		return nil
+	}
+
+	var sigAlgs []SignatureScheme
+	switch pub := priv.Public().(type) {
+	case *ecdsa.PublicKey:
+		if version != VersionTLS13 {
+			// In TLS 1.2 and earlier, ECDSA algorithms are not
+			// constrained to a single curve.
+			sigAlgs = []SignatureScheme{
+				ECDSAWithP256AndSHA256,
+				ECDSAWithP384AndSHA384,
+				ECDSAWithP521AndSHA512,
+				ECDSAWithSHA1,
+			}
+			break
+		}
+		switch pub.Curve {
+		case elliptic.P256():
+			sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256}
+		case elliptic.P384():
+			sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384}
+		case elliptic.P521():
+			sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512}
+		default:
+			return nil
+		}
+	case *rsa.PublicKey:
+		size := pub.Size()
+		sigAlgs = make([]SignatureScheme, 0, len(rsaSignatureSchemes))
+		for _, candidate := range rsaSignatureSchemes {
+			if size >= candidate.minModulusBytes && version <= candidate.maxVersion {
+				sigAlgs = append(sigAlgs, candidate.scheme)
+			}
+		}
+	case ed25519.PublicKey:
+		sigAlgs = []SignatureScheme{Ed25519}
+	default:
+		return nil
+	}
+
+	if cert.SupportedSignatureAlgorithms != nil {
+		var filteredSigAlgs []SignatureScheme
+		for _, sigAlg := range sigAlgs {
+			if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) {
+				filteredSigAlgs = append(filteredSigAlgs, sigAlg)
+			}
+		}
+		return filteredSigAlgs
+	}
+	return sigAlgs
+}
+
+// selectSignatureScheme picks a SignatureScheme from the peer's preference list
+// that works with the selected certificate. It's only called for protocol
+// versions that support signature algorithms, so TLS 1.2 and 1.3.
+func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) {
+	supportedAlgs := signatureSchemesForCertificate(vers, c)
+	if len(supportedAlgs) == 0 {
+		return 0, unsupportedCertificateError(c)
+	}
+	if len(peerAlgs) == 0 && vers == VersionTLS12 {
+		// For TLS 1.2, if the client didn't send signature_algorithms then we
+		// can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1.
+		peerAlgs = []SignatureScheme{PKCS1WithSHA1, ECDSAWithSHA1}
+	}
+	// Pick signature scheme in the peer's preference order, as our
+	// preference order is not configurable.
+	for _, preferredAlg := range peerAlgs {
+		if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, fipsSupportedSignatureAlgorithms) {
+			continue
+		}
+		if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
+			return preferredAlg, nil
+		}
+	}
+	return 0, errors.New("tls: peer doesn't support any of the certificate's signature algorithms")
+}
+
+// unsupportedCertificateError returns a helpful error for certificates with
+// an unsupported private key.
+func unsupportedCertificateError(cert *Certificate) error {
+	switch cert.PrivateKey.(type) {
+	case rsa.PrivateKey, ecdsa.PrivateKey:
+		return fmt.Errorf("tls: unsupported certificate: private key is %T, expected *%T",
+			cert.PrivateKey, cert.PrivateKey)
+	case *ed25519.PrivateKey:
+		return fmt.Errorf("tls: unsupported certificate: private key is *ed25519.PrivateKey, expected ed25519.PrivateKey")
+	}
+
+	signer, ok := cert.PrivateKey.(crypto.Signer)
+	if !ok {
+		return fmt.Errorf("tls: certificate private key (%T) does not implement crypto.Signer",
+			cert.PrivateKey)
+	}
+
+	switch pub := signer.Public().(type) {
+	case *ecdsa.PublicKey:
+		switch pub.Curve {
+		case elliptic.P256():
+		case elliptic.P384():
+		case elliptic.P521():
+		default:
+			return fmt.Errorf("tls: unsupported certificate curve (%s)", pub.Curve.Params().Name)
+		}
+	case *rsa.PublicKey:
+		return fmt.Errorf("tls: certificate RSA key size too small for supported signature algorithms")
+	case ed25519.PublicKey:
+	default:
+		return fmt.Errorf("tls: unsupported certificate key (%T)", pub)
+	}
+
+	if cert.SupportedSignatureAlgorithms != nil {
+		return fmt.Errorf("tls: peer doesn't support the certificate custom signature algorithms")
+	}
+
+	return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey)
+}

+ 102 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/boring.go

@@ -0,0 +1,102 @@
+// 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.
+
+//go:build boringcrypto
+
+package tls
+
+import "crypto/internal/boring/fipstls"
+
+// The FIPS-only policies enforced here currently match BoringSSL's
+// ssl_policy_fips_202205.
+
+// needFIPS returns fipstls.Required(); it avoids a new import in common.go.
+func needFIPS() bool {
+	return fipstls.Required()
+}
+
+// fipsMinVersion replaces c.minVersion in FIPS-only mode.
+func fipsMinVersion(c *Config) uint16 {
+	// FIPS requires TLS 1.2 or TLS 1.3.
+	return VersionTLS12
+}
+
+// fipsMaxVersion replaces c.maxVersion in FIPS-only mode.
+func fipsMaxVersion(c *Config) uint16 {
+	// FIPS requires TLS 1.2 or TLS 1.3.
+	return VersionTLS13
+}
+
+// default defaultFIPSCurvePreferences is the FIPS-allowed curves,
+// in preference order (most preferable first).
+var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384}
+
+// fipsCurvePreferences replaces c.curvePreferences in FIPS-only mode.
+func fipsCurvePreferences(c *Config) []CurveID {
+	if c == nil || len(c.CurvePreferences) == 0 {
+		return defaultFIPSCurvePreferences
+	}
+	var list []CurveID
+	for _, id := range c.CurvePreferences {
+		for _, allowed := range defaultFIPSCurvePreferences {
+			if id == allowed {
+				list = append(list, id)
+				break
+			}
+		}
+	}
+	return list
+}
+
+// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
+var defaultCipherSuitesFIPS = []uint16{
+	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+	TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+	TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+	TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+}
+
+// fipsCipherSuites replaces c.cipherSuites in FIPS-only mode.
+func fipsCipherSuites(c *Config) []uint16 {
+	if c == nil || c.CipherSuites == nil {
+		return defaultCipherSuitesFIPS
+	}
+	list := make([]uint16, 0, len(defaultCipherSuitesFIPS))
+	for _, id := range c.CipherSuites {
+		for _, allowed := range defaultCipherSuitesFIPS {
+			if id == allowed {
+				list = append(list, id)
+				break
+			}
+		}
+	}
+	return list
+}
+
+// defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3.
+var defaultCipherSuitesTLS13FIPS = []uint16{
+	TLS_AES_128_GCM_SHA256,
+	TLS_AES_256_GCM_SHA384,
+}
+
+// fipsSupportedSignatureAlgorithms currently are a subset of
+// defaultSupportedSignatureAlgorithms without Ed25519, SHA-1, and P-521.
+var fipsSupportedSignatureAlgorithms = []SignatureScheme{
+	PSSWithSHA256,
+	PSSWithSHA384,
+	PSSWithSHA512,
+	PKCS1WithSHA256,
+	ECDSAWithP256AndSHA256,
+	PKCS1WithSHA384,
+	ECDSAWithP384AndSHA384,
+	PKCS1WithSHA512,
+}
+
+// supportedSignatureAlgorithms returns the supported signature algorithms.
+func supportedSignatureAlgorithms() []SignatureScheme {
+	if !needFIPS() {
+		return defaultSupportedSignatureAlgorithms
+	}
+	return fipsSupportedSignatureAlgorithms
+}

+ 95 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/cache.go

@@ -0,0 +1,95 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"crypto/x509"
+	"runtime"
+	"sync"
+	"sync/atomic"
+)
+
+type cacheEntry struct {
+	refs atomic.Int64
+	cert *x509.Certificate
+}
+
+// certCache implements an intern table for reference counted x509.Certificates,
+// implemented in a similar fashion to BoringSSL's CRYPTO_BUFFER_POOL. This
+// allows for a single x509.Certificate to be kept in memory and referenced from
+// multiple Conns. Returned references should not be mutated by callers. Certificates
+// are still safe to use after they are removed from the cache.
+//
+// Certificates are returned wrapped in an activeCert struct that should be held by
+// the caller. When references to the activeCert are freed, the number of references
+// to the certificate in the cache is decremented. Once the number of references
+// reaches zero, the entry is evicted from the cache.
+//
+// The main difference between this implementation and CRYPTO_BUFFER_POOL is that
+// CRYPTO_BUFFER_POOL is a more  generic structure which supports blobs of data,
+// rather than specific structures. Since we only care about x509.Certificates,
+// certCache is implemented as a specific cache, rather than a generic one.
+//
+// See https://boringssl.googlesource.com/boringssl/+/master/include/openssl/pool.h
+// and https://boringssl.googlesource.com/boringssl/+/master/crypto/pool/pool.c
+// for the BoringSSL reference.
+type certCache struct {
+	sync.Map
+}
+
+var globalCertCache = new(certCache)
+
+// activeCert is a handle to a certificate held in the cache. Once there are
+// no alive activeCerts for a given certificate, the certificate is removed
+// from the cache by a finalizer.
+type activeCert struct {
+	cert *x509.Certificate
+}
+
+// active increments the number of references to the entry, wraps the
+// certificate in the entry in an activeCert, and sets the finalizer.
+//
+// Note that there is a race between active and the finalizer set on the
+// returned activeCert, triggered if active is called after the ref count is
+// decremented such that refs may be > 0 when evict is called. We consider this
+// safe, since the caller holding an activeCert for an entry that is no longer
+// in the cache is fine, with the only side effect being the memory overhead of
+// there being more than one distinct reference to a certificate alive at once.
+func (cc *certCache) active(e *cacheEntry) *activeCert {
+	e.refs.Add(1)
+	a := &activeCert{e.cert}
+	runtime.SetFinalizer(a, func(_ *activeCert) {
+		if e.refs.Add(-1) == 0 {
+			cc.evict(e)
+		}
+	})
+	return a
+}
+
+// evict removes a cacheEntry from the cache.
+func (cc *certCache) evict(e *cacheEntry) {
+	cc.Delete(string(e.cert.Raw))
+}
+
+// newCert returns a x509.Certificate parsed from der. If there is already a copy
+// of the certificate in the cache, a reference to the existing certificate will
+// be returned. Otherwise, a fresh certificate will be added to the cache, and
+// the reference returned. The returned reference should not be mutated.
+func (cc *certCache) newCert(der []byte) (*activeCert, error) {
+	if entry, ok := cc.Load(string(der)); ok {
+		return cc.active(entry.(*cacheEntry)), nil
+	}
+
+	cert, err := x509.ParseCertificate(der)
+	if err != nil {
+		return nil, err
+	}
+
+	entry := &cacheEntry{cert: cert}
+	if entry, loaded := cc.LoadOrStore(string(der), entry); loaded {
+		return cc.active(entry.(*cacheEntry)), nil
+	}
+	return cc.active(entry), nil
+}

+ 684 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/cipher_suites.go

@@ -0,0 +1,684 @@
+// 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,
+}
+
+// aesgcmPreferred returns whether the first known cipher in the preference list
+// is an AES-GCM cipher, implying the peer has hardware support for it.
+func aesgcmPreferred(ciphers []uint16) bool {
+	for _, cID := range ciphers {
+		if c := cipherSuiteByID(cID); c != nil {
+			return aesgcmCiphers[cID]
+		}
+		if c := cipherSuiteTLS13ByID(cID); c != nil {
+			return aesgcmCiphers[cID]
+		}
+	}
+	return false
+}
+
+func cipherRC4(key, iv []byte, isRead bool) any {
+	cipher, _ := rc4.NewCipher(key)
+	return cipher
+}
+
+func cipher3DES(key, iv []byte, isRead bool) any {
+	block, _ := des.NewTripleDESCipher(key)
+	if isRead {
+		return cipher.NewCBCDecrypter(block, iv)
+	}
+	return cipher.NewCBCEncrypter(block, iv)
+}
+
+func cipherAES(key, iv []byte, isRead bool) any {
+	block, _ := aes.NewCipher(key)
+	if isRead {
+		return cipher.NewCBCDecrypter(block, iv)
+	}
+	return cipher.NewCBCEncrypter(block, iv)
+}
+
+// macSHA1 returns a SHA-1 based constant time MAC.
+func macSHA1(key []byte) hash.Hash {
+	h := sha1.New
+	h = newConstantTimeHash(h)
+	return hmac.New(h, key)
+}
+
+// macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and
+// is currently only used in disabled-by-default cipher suites.
+func macSHA256(key []byte) hash.Hash {
+	return hmac.New(sha256.New, key)
+}
+
+type aead interface {
+	cipher.AEAD
+
+	// explicitNonceLen returns the number of bytes of explicit nonce
+	// included in each record. This is eight for older AEADs and
+	// zero for modern ones.
+	explicitNonceLen() int
+}
+
+const (
+	aeadNonceLength   = 12
+	noncePrefixLength = 4
+)
+
+// prefixNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
+// each call.
+type prefixNonceAEAD struct {
+	// nonce contains the fixed part of the nonce in the first four bytes.
+	nonce [aeadNonceLength]byte
+	aead  cipher.AEAD
+}
+
+func (f *prefixNonceAEAD) NonceSize() int        { return aeadNonceLength - noncePrefixLength }
+func (f *prefixNonceAEAD) Overhead() int         { return f.aead.Overhead() }
+func (f *prefixNonceAEAD) explicitNonceLen() int { return f.NonceSize() }
+
+func (f *prefixNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+	copy(f.nonce[4:], nonce)
+	return f.aead.Seal(out, f.nonce[:], plaintext, additionalData)
+}
+
+func (f *prefixNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	copy(f.nonce[4:], nonce)
+	return f.aead.Open(out, f.nonce[:], ciphertext, additionalData)
+}
+
+// xorNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
+// before each call.
+type xorNonceAEAD struct {
+	nonceMask [aeadNonceLength]byte
+	aead      cipher.AEAD
+}
+
+func (f *xorNonceAEAD) NonceSize() int        { return 8 } // 64-bit sequence number
+func (f *xorNonceAEAD) Overhead() int         { return f.aead.Overhead() }
+func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
+
+func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+	for i, b := range nonce {
+		f.nonceMask[4+i] ^= b
+	}
+	result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
+	for i, b := range nonce {
+		f.nonceMask[4+i] ^= b
+	}
+
+	return result
+}
+
+func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+	for i, b := range nonce {
+		f.nonceMask[4+i] ^= b
+	}
+	result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
+	for i, b := range nonce {
+		f.nonceMask[4+i] ^= b
+	}
+
+	return result, err
+}
+
+func aeadAESGCM(key, noncePrefix []byte) aead {
+	if len(noncePrefix) != noncePrefixLength {
+		panic("tls: internal error: wrong nonce length")
+	}
+	aes, err := aes.NewCipher(key)
+	if err != nil {
+		panic(err)
+	}
+	var aead cipher.AEAD
+	aead, err = cipher.NewGCM(aes)
+	if err != nil {
+		panic(err)
+	}
+
+	ret := &prefixNonceAEAD{aead: aead}
+	copy(ret.nonce[:], noncePrefix)
+	return ret
+}
+
+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)
+	}
+	var aead cipher.AEAD
+	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
+)

+ 1499 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/common.go

@@ -0,0 +1,1499 @@
+// 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/tls"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"strings"
+	"sync"
+	"time"
+
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
+)
+
+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
+)
+
+// VersionName returns the name for the provided TLS version number
+// (e.g. "TLS 1.3"), or a fallback representation of the value if the
+// version is not implemented by this package.
+func VersionName(version uint16) string {
+	switch version {
+	case VersionSSL30:
+		return "SSLv3"
+	case VersionTLS10:
+		return "TLS 1.0"
+	case VersionTLS11:
+		return "TLS 1.1"
+	case VersionTLS12:
+		return "TLS 1.2"
+	case VersionTLS13:
+		return "TLS 1.3"
+	default:
+		return fmt.Sprintf("0x%04X", version)
+	}
+}
+
+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
+	extensionExtendedMasterSecret    uint16 = 23
+	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
+	extensionQUICTransportParameters uint16 = 57
+	extensionRenegotiationInfo       uint16 = 0xff01
+)
+
+// TLS signaling cipher suite values
+const (
+	scsvRenegotiation uint16 = 0x00ff
+)
+
+// CurveID is a tls.CurveID
+type CurveID = tls.CurveID
+
+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
+)
+
+// 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
+
+// defaultSupportedSignatureAlgorithms 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 defaultSupportedSignatureAlgorithms = []SignatureScheme{
+	PSSWithSHA256,
+	ECDSAWithP256AndSHA256,
+	Ed25519,
+	PSSWithSHA384,
+	PSSWithSHA512,
+	PKCS1WithSHA256,
+	PKCS1WithSHA384,
+	PKCS1WithSHA512,
+	ECDSAWithP384AndSHA384,
+	ECDSAWithP521AndSHA512,
+	PKCS1WithSHA1,
+	ECDSAWithSHA1,
+}
+
+// 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
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState = tls.ConnectionState
+
+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 and its contents should not be modified.
+	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 and its contents should not be modified.
+	VerifiedChains [][]*x509.Certificate
+
+	// 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
+	// resumed connections that don't support Extended Master Secret (RFC 7627).
+	TLSUnique []byte
+
+	// 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.
+//
+// There are conditions in which the returned values 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.
+// func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
+// 	return cs.ekm(label, context, length)
+// }
+
+// ClientAuthType is tls.ClientAuthType
+type ClientAuthType = tls.ClientAuthType
+
+const (
+	NoClientCert               = tls.NoClientCert
+	RequestClientCert          = tls.RequestClientCert
+	RequireAnyClientCert       = tls.RequireAnyClientCert
+	VerifyClientCertIfGiven    = tls.VerifyClientCertIfGiven
+	RequireAndVerifyClientCert = tls.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
+	}
+}
+
+type ClientSessionCache = tls.ClientSessionCache
+
+// SignatureScheme is a tls.SignatureScheme
+type SignatureScheme = tls.SignatureScheme
+
+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 = tls.ClientHelloInfo
+
+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
+
+	// 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
+
+	// 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 = tls.CertificateRequestInfo
+
+type certificateRequestInfo struct {
+	// AcceptableCAs contains zero or more, DER-encoded, X.501
+	// Distinguished Names. These are the names of root or intermediate CAs
+	// that the server wishes the returned certificate to be signed by. An
+	// empty slice indicates that the server has no preference.
+	AcceptableCAs [][]byte
+
+	// SignatureSchemes lists the signature schemes that the server is
+	// willing to verify.
+	SignatureSchemes []SignatureScheme
+
+	// Version is the TLS version that was negotiated for this connection.
+	Version uint16
+
+	// ctx is the context of the handshake that is in progress.
+	ctx context.Context
+}
+
+// Context returns the context of the handshake that is in progress.
+// This context is a child of the context passed to HandshakeContext,
+// if any, and is canceled when the handshake concludes.
+func (c *certificateRequestInfo) Context() context.Context {
+	return c.ctx
+}
+
+// RenegotiationSupport enumerates the different levels of support for TLS
+// renegotiation. TLS renegotiation is the act of performing subsequent
+// handshakes on a connection after the first. This significantly complicates
+// 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 = tls.RenegotiationSupport
+
+const (
+	// RenegotiateNever disables renegotiation.
+	RenegotiateNever = tls.RenegotiateNever
+
+	// RenegotiateOnceAsClient allows a remote server to request
+	// renegotiation once per connection.
+	RenegotiateOnceAsClient = tls.RenegotiateOnceAsClient
+
+	// RenegotiateFreelyAsClient allows a remote server to repeatedly
+	// request renegotiation.
+	RenegotiateFreelyAsClient = tls.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 = tls.Config
+
+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.
+	//
+	// Once a Certificate is returned it should not be modified.
+	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.
+	//
+	// Once a Certificate is returned it should not be modified.
+	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 (on the
+	// client when InsecureSkipVerify is set, or on a server when ClientAuth is
+	// RequestClientCert or RequireAnyClientCert), then this callback will be
+	// considered but the verifiedChains argument will always be nil. When
+	// ClientAuth is NoClientCert, this callback is not called on the server.
+	// rawCerts may be empty on the server if ClientAuth is RequestClientCert or
+	// VerifyClientCertIfGiven.
+	//
+	// This callback is not invoked on resumed connections, as certificates are
+	// not re-verified on resumption.
+	//
+	// verifiedChains and its contents should not be modified.
+	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,
+	// including resumptions, 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.
+	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
+
+	// UnwrapSession is called on the server to turn a ticket/identity
+	// previously produced by [WrapSession] into a usable session.
+	//
+	// UnwrapSession will usually either decrypt a session state in the ticket
+	// (for example with [Config.EncryptTicket]), or use the ticket as a handle
+	// to recover a previously stored state. It must use [ParseSessionState] to
+	// deserialize the session state.
+	//
+	// If UnwrapSession returns an error, the connection is terminated. If it
+	// returns (nil, nil), the session is ignored. crypto/tls may still choose
+	// not to resume the returned session.
+	UnwrapSession func(identity []byte, cs ConnectionState) (*SessionState, error)
+
+	// WrapSession is called on the server to produce a session ticket/identity.
+	//
+	// WrapSession must serialize the session state with [SessionState.Bytes].
+	// It may then encrypt the serialized state (for example with
+	// [Config.DecryptTicket]) and use it as the ticket, or store the state and
+	// return a handle for it.
+	//
+	// If WrapSession returns an error, the connection is terminated.
+	//
+	// Warning: the return value will be exposed on the wire and to clients in
+	// plaintext. The application is in charge of encrypting and authenticating
+	// it (and rotating keys) or returning high-entropy identifiers. Failing to
+	// do so correctly can compromise current, previous, and future connections
+	// depending on the protocol version.
+	WrapSession func(ConnectionState, *SessionState) ([]byte, error)
+
+	// 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
+
+	// 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
+
+	// mutex protects sessionTicketKeys and autoSessionTicketKeys.
+	mutex sync.RWMutex
+	// sessionTicketKeys contains zero or more ticket keys. If set, it means
+	// 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
+}
+
+// [Psiphon]
+type ExtraConfig struct {
+	// ClientHelloPRNG is used for Client Hello randomization and replay.
+	ClientHelloPRNG *prng.PRNG
+
+	// GetClientHelloRandom is used to supply a specific value in the TLS
+	// Client Hello random field. This is used to send an anti-probing
+	// message, indistinguishable from random, that proves knowlegde of a
+	// shared secret key.
+	GetClientHelloRandom func() ([]byte, error)
+}
+
+const (
+	// 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 {
+	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[:])
+	// The first 16 bytes of the hash used to be exposed on the wire as a ticket
+	// prefix. They MUST NOT be used as a secret. In the future, it would make
+	// sense to use a proper KDF here, like HKDF with a fixed salt.
+	const legacyTicketKeyNameLen = 16
+	copy(key.aesKey[:], hashed[legacyTicketKeyNameLen:])
+	copy(key.hmacKey[:], hashed[legacyTicketKeyNameLen+len(key.aesKey):])
+	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 all 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,
+		UnwrapSession:               c.UnwrapSession,
+		WrapSession:                 c.WrapSession,
+		MinVersion:                  c.MinVersion,
+		MaxVersion:                  c.MaxVersion,
+		CurvePreferences:            c.CurvePreferences,
+		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
+		Renegotiation:               c.Renegotiation,
+		KeyLogWriter:                c.KeyLogWriter,
+		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 needFIPS() {
+		return fipsCipherSuites(c)
+	}
+	if c.CipherSuites != nil {
+		return c.CipherSuites
+	}
+	return defaultCipherSuites
+}
+
+var supportedVersions = []uint16{
+	VersionTLS13,
+	VersionTLS12,
+	VersionTLS11,
+	VersionTLS10,
+}
+
+// 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 needFIPS() && (v < fipsMinVersion(c) || v > fipsMaxVersion(c)) {
+			continue
+		}
+		if (c == nil || c.MinVersion == 0) &&
+			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) 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 needFIPS() {
+		return fipsCurvePreferences(c)
+	}
+	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{}
+	}
+	conf := fromConfig(config)
+	vers, ok := conf.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 := leafCertificate(c)
+		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, conf.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(conf, 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 && conf.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, conf.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 := leafCertificate(cert)
+		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 := fmt.Appendf(nil, "%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
+
+type Certificate = tls.Certificate
+
+// leaf returns the parsed leaf certificate, either from c.Leaf or by parsing
+// the corresponding c.Certificate[0].
+func leafCertificate(c *Certificate) (*x509.Certificate, error) {
+	if c.Leaf != nil {
+		return c.Leaf, nil
+	}
+	return x509.ParseCertificate(c.Certificate[0])
+}
+
+type handshakeMessage interface {
+	marshal() ([]byte, error)
+	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
+}
+
+// CertificateVerificationError is returned when certificate verification fails during the handshake.
+type CertificateVerificationError = tls.CertificateVerificationError

+ 1676 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/conn.go

@@ -0,0 +1,1676 @@
+// 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"
+)
+
+// 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
+	quic        *quicState                  // nil for non-QUIC connections
+
+	// isHandshakeComplete is true if the connection is currently transferring
+	// application data (i.e. is not currently processing a handshake).
+	// isHandshakeComplete is true implies handshakeErr == nil.
+	isHandshakeComplete atomic.Bool
+	// 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
+	extraConfig    *ExtraConfig
+	// handshakes counts the number of handshakes performed on the
+	// connection so far. If renegotiation is disabled then this is either
+	// zero or one.
+	handshakes       int
+	extMasterSecret  bool
+	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
+	// activeCertHandles contains the cache handles to certificates in
+	// peerCertificates that are used to track active references.
+	activeCertHandles []*activeCert
+	// verifiedChains contains the certificate chains that we built, as
+	// opposed to the ones presented by the server.
+	verifiedChains [][]*x509.Certificate
+	// 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
+	// or sending NewSessionTicket messages.
+	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 indicates whether Close has been call in the low bit.
+	// the rest of the bits are the number of goroutines in Conn.Write.
+	activeCall atomic.Int32
+
+	tmp [16]byte
+}
+
+// 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
+
+	level         QUICEncryptionLevel // current QUIC encryption level
+	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, level QUICEncryptionLevel, secret []byte) {
+	hc.trafficSecret = secret
+	hc.level = level
+	key, iv := suite.trafficKey(secret)
+	hc.cipher = suite.aead(key, iv)
+	for i := range hc.seq {
+		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.isHandshakeComplete.Load()
+
+	// 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)
+
+	if c.quic != nil {
+		return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with QUIC transport"))
+	}
+
+	// Read header, payload.
+	if err := c.readFromUntil(c.conn, recordHeaderLen); err != nil {
+		// RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify
+		// 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])
+	expectedVers := c.vers
+	if expectedVers == VersionTLS13 {
+		// All TLS 1.3 records are expected to have 0x0303 (1.2) after
+		// the initial hello (RFC 8446 Section 5.1).
+		expectedVers = VersionTLS12
+	}
+	n := int(hdr[3])<<8 | int(hdr[4])
+	if c.haveVers && vers != expectedVers {
+		c.sendAlert(alertProtocolVersion)
+		msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, expectedVers)
+		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 c.quic != nil {
+			return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+		}
+		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 {
+			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 recurs 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
+}
+
+// sendAlertLocked sends a TLS alert message.
+func (c *Conn) sendAlertLocked(err alert) error {
+	if c.quic != nil {
+		return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+	}
+
+	switch err {
+	case alertNoRenegotiation, alertCloseNotify:
+		c.tmp[0] = alertLevelWarning
+	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) {
+	if c.quic != nil {
+		if typ != recordTypeHandshake {
+			return 0, errors.New("tls: internal error: sending non-handshake message to QUIC transport")
+		}
+		c.quicWriteCryptoData(c.out.level, data)
+		if !c.buffering {
+			if _, err := c.flush(); err != nil {
+				return 0, err
+			}
+		}
+		return len(data), nil
+	}
+
+	outBufPtr := outBufPool.Get().(*[]byte)
+	outBuf := *outBufPtr
+	defer func() {
+		// 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
+}
+
+// writeHandshakeRecord writes a handshake message to the connection and updates
+// the record layer state. If transcript is non-nil the marshalled message is
+// written to it.
+func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) {
+	c.out.Lock()
+	defer c.out.Unlock()
+
+	data, err := msg.marshal()
+	if err != nil {
+		return 0, err
+	}
+	if transcript != nil {
+		transcript.Write(data)
+	}
+
+	return c.writeRecordLocked(recordTypeHandshake, data)
+}
+
+// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and
+// updates the record layer state.
+func (c *Conn) writeChangeCipherRecord() error {
+	c.out.Lock()
+	defer c.out.Unlock()
+	_, err := c.writeRecordLocked(recordTypeChangeCipherSpec, []byte{1})
+	return err
+}
+
+// [Psiphon]
+func ReadClientHelloRandom(data []byte) ([]byte, error) {
+	if len(data) < 1 {
+		return nil, errors.New("tls: missing message type")
+	}
+	if data[0] != typeClientHello {
+		return nil, errors.New("tls: unexpected message type")
+	}
+
+	// Unlike readHandshake, m is not retained and so making a copy of the
+	// input data is not necessary.
+
+	var m clientHelloMsg
+	if !m.unmarshal(data) {
+		return nil, errors.New("tls: unexpected message")
+	}
+
+	return m.random, nil
+}
+
+// readHandshakeBytes reads handshake data until c.hand contains at least n bytes.
+func (c *Conn) readHandshakeBytes(n int) error {
+	if c.quic != nil {
+		return c.quicReadHandshakeBytes(n)
+	}
+	for c.hand.Len() < n {
+		if err := c.readRecord(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// readHandshake reads the next handshake message from
+// the record layer. If transcript is non-nil, the message
+// is written to the passed transcriptHash.
+func (c *Conn) readHandshake(transcript transcriptHash) (any, error) {
+	if err := c.readHandshakeBytes(4); err != nil {
+		return nil, err
+	}
+	data := c.hand.Bytes()
+	n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+	if n > maxHandshake {
+		c.sendAlertLocked(alertInternalError)
+		return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake))
+	}
+	if err := c.readHandshakeBytes(4 + n); err != nil {
+		return nil, err
+	}
+	data = c.hand.Next(4 + n)
+	return c.unmarshalHandshakeMessage(data, transcript)
+}
+
+func (c *Conn) unmarshalHandshakeMessage(data []byte, transcript transcriptHash) (handshakeMessage, error) {
+	var m handshakeMessage
+	switch data[0] {
+	case typeHelloRequest:
+		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))
+	}
+
+	if transcript != nil {
+		transcript.Write(data)
+	}
+
+	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 := c.activeCall.Load()
+		if x&1 != 0 {
+			return 0, net.ErrClosed
+		}
+		if c.activeCall.CompareAndSwap(x, x+2) {
+			break
+		}
+	}
+	defer c.activeCall.Add(-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.isHandshakeComplete.Load() {
+		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(nil)
+	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()
+
+	c.isHandshakeComplete.Store(false)
+	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(nil)
+	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)
+	}
+	// The QUIC layer is supposed to treat an unexpected post-handshake CertificateRequest
+	// as a QUIC-level PROTOCOL_VIOLATION error (RFC 9001, Section 4.4). Returning an
+	// unexpected_message alert here doesn't provide it with enough information to distinguish
+	// this condition from other unexpected messages. This is probably fine.
+	c.sendAlert(alertUnexpectedMessage)
+	return fmt.Errorf("tls: received unexpected handshake message of type %T", msg)
+}
+
+func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
+	if c.quic != nil {
+		c.sendAlert(alertUnexpectedMessage)
+		return c.in.setErrorLocked(errors.New("tls: received unexpected key update message"))
+	}
+
+	cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
+	if cipherSuite == nil {
+		return c.in.setErrorLocked(c.sendAlert(alertInternalError))
+	}
+
+	newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret)
+	c.in.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret)
+
+	if keyUpdate.updateRequested {
+		c.out.Lock()
+		defer c.out.Unlock()
+
+		msg := &keyUpdateMsg{}
+		msgBytes, err := msg.marshal()
+		if err != nil {
+			return err
+		}
+		_, err = c.writeRecordLocked(recordTypeHandshake, msgBytes)
+		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, QUICEncryptionLevelInitial, 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 = c.activeCall.Load()
+		if x&1 != 0 {
+			return net.ErrClosed
+		}
+		if c.activeCall.CompareAndSwap(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.isHandshakeComplete.Load() {
+		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
+	}
+	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.isHandshakeComplete.Load() {
+		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.
+//
+// In order to avoid denial of service attacks, the maximum RSA key size allowed
+// in certificates sent by either the TLS server or client is limited to 8192
+// bits. This limit can be overridden by setting tlsmaxrsasize in the GODEBUG
+// environment variable (e.g. GODEBUG=tlsmaxrsasize=4096).
+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.isHandshakeComplete.Load() {
+		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()
+
+	if c.quic != nil {
+		c.quic.cancelc = handshakeCtx.Done()
+		c.quic.cancel = cancel
+	} else if ctx.Done() != nil {
+		// Start the "interrupter" goroutine, if this context might be canceled.
+		// (The background context cannot).
+		//
+		// The interrupter goroutine waits for the input context to be done and
+		// closes the connection if this happens before the function returns.
+		done := make(chan struct{})
+		interruptRes := make(chan error, 1)
+		defer func() {
+			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.isHandshakeComplete.Load() {
+		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.isHandshakeComplete.Load() {
+		c.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
+	}
+	if c.handshakeErr != nil && c.isHandshakeComplete.Load() {
+		panic("tls: internal error: handshake returned an error but is marked successful")
+	}
+
+	if c.quic != nil {
+		if c.handshakeErr == nil {
+			c.quicHandshakeComplete()
+			// Provide the 1-RTT read secret now that the handshake is complete.
+			// The QUIC layer MUST NOT decrypt 1-RTT packets prior to completing
+			// the handshake (RFC 9001, Section 5.7).
+			c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret)
+		} else {
+			var a alert
+			c.out.Lock()
+			if !errors.As(c.out.err, &a) {
+				a = alertInternalError
+			}
+			c.out.Unlock()
+			// Return an error which wraps both the handshake error and
+			// any alert error we may have sent, or alertInternalError
+			// if we didn't send an alert.
+			// Truncate the text of the alert to 0 characters.
+			c.handshakeErr = fmt.Errorf("%w%.0w", c.handshakeErr, AlertError(a))
+		}
+		close(c.quic.blockedc)
+		close(c.quic.signalc)
+	}
+
+	return c.handshakeErr
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	return c.connectionStateLocked()
+}
+
+func (c *Conn) connectionStateLocked() ConnectionState {
+	var state connectionState
+	state.HandshakeComplete = c.isHandshakeComplete.Load()
+	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
+	state.SignedCertificateTimestamps = c.scts
+	state.OCSPResponse = c.ocspResponse
+	if (!c.didResume || c.extMasterSecret) && 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 toConnectionState(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.isHandshakeComplete.Load() {
+		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)
+}

+ 1150 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_client.go

@@ -0,0 +1,1150 @@
+// 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/ecdh"
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/rsa"
+	"crypto/subtle"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"hash"
+	"io"
+	"net"
+	"strings"
+	"time"
+)
+
+type clientHandshakeState struct {
+	c            *Conn
+	ctx          context.Context
+	serverHello  *serverHelloMsg
+	hello        *clientHelloMsg
+	suite        *cipherSuite
+	finishedHash finishedHash
+	masterSecret []byte
+	session      *sessionState // the session being resumed
+	ticket       []byte        // a fresh ticket received during this handshake
+}
+
+var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme
+
+func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, 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.supportedVersions(roleClient)
+	if len(supportedVersions) == 0 {
+		return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
+	}
+
+	clientHelloVersion := config.maxSupportedVersion(roleClient)
+	// The version at the beginning of the ClientHello was capped at TLS 1.2
+	// for compatibility reasons. The supported_versions extension is used
+	// to negotiate versions now. See RFC 8446, Section 4.2.1.
+	if clientHelloVersion > VersionTLS12 {
+		clientHelloVersion = VersionTLS12
+	}
+
+	hello := &clientHelloMsg{
+		vers:                         clientHelloVersion,
+		compressionMethods:           []uint8{compressionNone},
+		random:                       make([]byte, 32),
+		extendedMasterSecret:         true,
+		ocspStapling:                 true,
+		scts:                         true,
+		serverName:                   hostnameInSNI(config.ServerName),
+		supportedCurves:              config.curvePreferences(),
+		supportedPoints:              []uint8{pointFormatUncompressed},
+		secureRenegotiationSupported: true,
+		alpnProtocols:                config.NextProtos,
+		supportedVersions:            supportedVersions,
+	}
+
+	// [Psiphon]
+	if c.extraConfig != nil {
+		hello.PRNG = c.extraConfig.ClientHelloPRNG
+		if c.extraConfig.GetClientHelloRandom != nil {
+			helloRandom, err := c.extraConfig.GetClientHelloRandom()
+			if err == nil && len(helloRandom) != 32 {
+				err = errors.New("invalid length")
+			}
+			if err != nil {
+				return nil, nil, errors.New("tls: GetClientHelloRandom failed: " + err.Error())
+			}
+			copy(hello.random, helloRandom)
+		}
+	}
+
+	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)
+	}
+
+	// [Psiphon]
+	var err error
+	if c.extraConfig == nil || c.extraConfig.GetClientHelloRandom == nil {
+
+		_, 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).
+	//
+	// The session ID is not set for QUIC connections (see RFC 9001, Section 8.4).
+	if c.quic == nil {
+		hello.sessionId = make([]byte, 32)
+		if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil {
+			return nil, nil, errors.New("tls: short read from Rand: " + err.Error())
+		}
+	}
+
+	if hello.vers >= VersionTLS12 {
+		hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+	}
+	if testingOnlyForceClientHelloSignatureAlgorithms != nil {
+		hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
+	}
+
+	var key *ecdh.PrivateKey
+	if hello.supportedVersions[0] == VersionTLS13 {
+		// Reset the list of ciphers when the client only supports TLS 1.3.
+		if len(hello.supportedVersions) == 1 {
+			hello.cipherSuites = nil
+		}
+		if needFIPS() {
+			hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13FIPS...)
+		} else if hasAESGCMHardwareSupport {
+			hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
+		} else {
+			hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
+		}
+
+		curveID := config.curvePreferences()[0]
+		if _, ok := curveForCurveID(curveID); !ok {
+			return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
+		}
+		key, err = generateECDHEKey(config.rand(), curveID)
+		if err != nil {
+			return nil, nil, err
+		}
+		hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}}
+	}
+
+	if c.quic != nil {
+		p, err := c.quicGetTransportParameters()
+		if err != nil {
+			return nil, nil, err
+		}
+		if p == nil {
+			p = []byte{}
+		}
+		hello.quicTransportParameters = p
+	}
+
+	return hello, key, nil
+}
+
+func (c *Conn) clientHandshake(ctx context.Context) (err error) {
+	if c.config == nil {
+		c.config = fromConfig(defaultConfig())
+	}
+
+	// This may be a renegotiation handshake, in which case some fields
+	// need to be reset.
+	c.didResume = false
+
+	hello, ecdheKey, err := c.makeClientHello()
+	if err != nil {
+		return err
+	}
+	c.serverName = hello.serverName
+
+	session, earlySecret, binderKey, err := c.loadSession(hello)
+	if err != nil {
+		return err
+	}
+	if 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 {
+				if cacheKey := c.clientSessionCacheKey(); cacheKey != "" {
+					c.config.ClientSessionCache.Put(cacheKey, nil)
+				}
+			}
+		}()
+	}
+
+	if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
+		return err
+	}
+
+	if hello.earlyData {
+		suite := cipherSuiteTLS13ByID(session.cipherSuite)
+		transcript := suite.hash.New()
+		if err := transcriptMsg(hello, transcript); err != nil {
+			return err
+		}
+		earlyTrafficSecret := suite.deriveSecret(earlySecret, clientEarlyTrafficLabel, transcript)
+		c.quicSetWriteSecret(QUICEncryptionLevelEarly, suite.id, earlyTrafficSecret)
+	}
+
+	// serverHelloMsg is not included in the transcript
+	msg, err := c.readHandshake(nil)
+	if err != nil {
+		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,
+			ecdheKey:    ecdheKey,
+			session:     session,
+			earlySecret: earlySecret,
+			binderKey:   binderKey,
+		}
+
+		// In TLS 1.3, session tickets are delivered after the handshake.
+		return hs.handshake()
+	}
+
+	hs := &clientHandshakeState{
+		c:           c,
+		ctx:         ctx,
+		serverHello: serverHello,
+		hello:       hello,
+		session:     session,
+	}
+
+	if err := hs.handshake(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c *Conn) loadSession(hello *clientHelloMsg) (
+	session *sessionState, earlySecret, binderKey []byte, err error) {
+	if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
+		return nil, 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, nil
+	}
+
+	// Try to resume a previously negotiated TLS session, if available.
+	cacheKey := c.clientSessionCacheKey()
+	if cacheKey == "" {
+		return nil, nil, nil, nil
+	}
+	cs, ok := c.config.ClientSessionCache.Get(cacheKey)
+	if !ok || cs == nil {
+		return nil, nil, nil, nil
+	}
+	session = fromClientSessionState(cs).session
+
+	// Check that version used for the previous session is still valid.
+	versOk := false
+	for _, v := range hello.supportedVersions {
+		if v == session.version {
+			versOk = true
+			break
+		}
+	}
+	if !versOk {
+		return nil, 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.time().After(session.peerCertificates[0].NotAfter) {
+		// Expired certificate, delete the entry.
+		c.config.ClientSessionCache.Put(cacheKey, nil)
+		return nil, nil, nil, nil
+	}
+	if !c.config.InsecureSkipVerify {
+		if len(session.verifiedChains) == 0 {
+			// The original connection had InsecureSkipVerify, while this doesn't.
+			return nil, nil, nil, nil
+		}
+		if err := session.peerCertificates[0].VerifyHostname(c.config.ServerName); err != nil {
+			return nil, nil, nil, nil
+		}
+	}
+
+	if session.version != 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 nil, nil, nil, nil
+		}
+
+		hello.sessionTicket = fromClientSessionState(cs).ticket
+		return
+	}
+
+	// Check that the session ticket is not expired.
+	if c.config.time().After(time.Unix(int64(session.useBy), 0)) {
+		c.config.ClientSessionCache.Put(cacheKey, nil)
+		return nil, 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 nil, 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 nil, nil, nil, nil
+	}
+
+	if c.quic != nil && session.EarlyData {
+		// For 0-RTT, the cipher suite has to match exactly, and we need to be
+		// offering the same ALPN.
+		if mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil {
+			for _, alpn := range hello.alpnProtocols {
+				if alpn == session.alpnProtocol {
+					hello.earlyData = true
+					break
+				}
+			}
+		}
+	}
+
+	// Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
+	ticketAge := c.config.time().Sub(time.Unix(int64(session.createdAt), 0))
+	identity := pskIdentity{
+		label:               fromClientSessionState(cs).ticket,
+		obfuscatedTicketAge: uint32(ticketAge/time.Millisecond) + 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.
+	earlySecret = cipherSuite.extract(session.secret, nil)
+	binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
+	transcript := cipherSuite.hash.New()
+	helloBytes, err := hello.marshalWithoutBinders()
+	if err != nil {
+		return nil, nil, nil, err
+	}
+	transcript.Write(helloBytes)
+	pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)}
+	if err := hello.updateBinders(pskBinders); err != nil {
+		return nil, nil, nil, err
+	}
+
+	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()
+	}
+
+	if err := transcriptMsg(hs.hello, &hs.finishedHash); err != nil {
+		return err
+	}
+	if err := transcriptMsg(hs.serverHello, &hs.finishedHash); err != nil {
+		return err
+	}
+
+	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
+		}
+	}
+	if err := hs.saveSessionTicket(); err != nil {
+		return err
+	}
+
+	c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
+	c.isHandshakeComplete.Store(true)
+
+	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(&hs.finishedHash)
+	if err != nil {
+		return err
+	}
+	certMsg, ok := msg.(*certificateMsg)
+	if !ok || len(certMsg.certificates) == 0 {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certMsg, msg)
+	}
+
+	msg, err = c.readHandshake(&hs.finishedHash)
+	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")
+		}
+
+		c.ocspResponse = cs.response
+
+		msg, err = c.readHandshake(&hs.finishedHash)
+		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 {
+		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
+		if err != nil {
+			c.sendAlert(alertUnexpectedMessage)
+			return err
+		}
+
+		msg, err = c.readHandshake(&hs.finishedHash)
+		if err != nil {
+			return err
+		}
+	}
+
+	var chainToSend *Certificate
+	var certRequested bool
+	certReq, ok := msg.(*certificateRequestMsg)
+	if ok {
+		certRequested = true
+
+		cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
+		if chainToSend, err = c.getClientCertificate(cri); err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+
+		msg, err = c.readHandshake(&hs.finishedHash)
+		if err != nil {
+			return err
+		}
+	}
+
+	shd, ok := msg.(*serverHelloDoneMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(shd, msg)
+	}
+
+	// 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
+		if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); 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 {
+		if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil {
+			return err
+		}
+	}
+
+	if hs.serverHello.extendedMasterSecret {
+		c.extMasterSecret = true
+		hs.masterSecret = extMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
+			hs.finishedHash.Sum())
+	} else {
+		hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
+			hs.hello.random, hs.serverHello.random)
+	}
+	if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: failed to write to key log: " + err.Error())
+	}
+
+	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)
+		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
+		}
+
+		if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil {
+			return err
+		}
+	}
+
+	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, false); 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.version != 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")
+	}
+
+	// RFC 7627, Section 5.3
+	if hs.session.extMasterSecret != hs.serverHello.extendedMasterSecret {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server resumed a session with a different EMS extension")
+	}
+
+	// Restore master secret and certificates from previous state
+	hs.masterSecret = hs.session.secret
+	c.extMasterSecret = hs.session.extMasterSecret
+	c.peerCertificates = hs.session.peerCertificates
+	c.activeCertHandles = hs.c.activeCertHandles
+	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, quic bool) error {
+	if serverProto == "" {
+		if quic && len(clientProtos) > 0 {
+			// RFC 9001, Section 8.1
+			return errors.New("tls: server did not select an ALPN protocol")
+		}
+		return nil
+	}
+	if len(clientProtos) == 0 {
+		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
+	}
+
+	// finishedMsg is included in the transcript, but not until after we
+	// check the client version, since the state before this message was
+	// sent is used during verification.
+	msg, err := c.readHandshake(nil)
+	if err != nil {
+		return err
+	}
+	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")
+	}
+
+	if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil {
+		return err
+	}
+
+	copy(out, verify)
+	return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+	if !hs.serverHello.ticketSupported {
+		return nil
+	}
+	c := hs.c
+
+	if !hs.hello.ticketSupported {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: server sent unrequested session ticket")
+	}
+
+	msg, err := c.readHandshake(&hs.finishedHash)
+	if err != nil {
+		return err
+	}
+	sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(sessionTicketMsg, msg)
+	}
+
+	hs.ticket = sessionTicketMsg.ticket
+	return nil
+}
+
+func (hs *clientHandshakeState) saveSessionTicket() error {
+	if hs.ticket == nil {
+		return nil
+	}
+	c := hs.c
+
+	cacheKey := c.clientSessionCacheKey()
+	if cacheKey == "" {
+		return nil
+	}
+
+	session, err := c.sessionState()
+	if err != nil {
+		return err
+	}
+	session.secret = hs.masterSecret
+
+	cs := &clientSessionState{ticket: hs.ticket, session: session}
+	c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(cs))
+	return nil
+}
+
+func (hs *clientHandshakeState) sendFinished(out []byte) error {
+	c := hs.c
+
+	if err := c.writeChangeCipherRecord(); err != nil {
+		return err
+	}
+
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+	if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
+		return err
+	}
+	copy(out, finished.verifyData)
+	return nil
+}
+
+// defaultMaxRSAKeySize is the maximum RSA key size in bits that we are willing
+// to verify the signatures of during a TLS handshake.
+const defaultMaxRSAKeySize = 8192
+
+func checkKeySize(n int) (max int, ok bool) {
+	return defaultMaxRSAKeySize, n <= defaultMaxRSAKeySize
+}
+
+// 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 {
+	activeHandles := make([]*activeCert, len(certificates))
+	certs := make([]*x509.Certificate, len(certificates))
+	for i, asn1Data := range certificates {
+		cert, err := globalCertCache.newCert(asn1Data)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: failed to parse certificate from server: " + err.Error())
+		}
+		if cert.cert.PublicKeyAlgorithm == x509.RSA {
+			n := cert.cert.PublicKey.(*rsa.PublicKey).N.BitLen()
+			if max, ok := checkKeySize(n); !ok {
+				c.sendAlert(alertBadCertificate)
+				return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", max)
+			}
+		}
+		activeHandles[i] = cert
+		certs[i] = cert.cert
+	}
+
+	if !c.config.InsecureSkipVerify {
+		opts := x509.VerifyOptions{
+			Roots:         c.config.RootCAs,
+			CurrentTime:   c.config.time(),
+			DNSName:       c.config.ServerName,
+			Intermediates: x509.NewCertPool(),
+		}
+
+		for _, cert := range certs[1:] {
+			opts.Intermediates.AddCert(cert)
+		}
+		var err error
+		c.verifiedChains, err = certs[0].Verify(opts)
+		if err != nil {
+			c.sendAlert(alertBadCertificate)
+			return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+		}
+	}
+
+	switch certs[0].PublicKey.(type) {
+	case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.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.activeCertHandles = activeHandles
+	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,
+	}
+
+	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 toCertificateRequestInfo(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 toCertificateRequestInfo(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 (c *Conn) clientSessionCacheKey() string {
+	if len(c.config.ServerName) > 0 {
+		return c.config.ServerName
+	}
+	if c.conn != nil {
+		return c.conn.RemoteAddr().String()
+	}
+	return ""
+}
+
+// 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
+}

+ 768 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_client_tls13.go

@@ -0,0 +1,768 @@
+// 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/ecdh"
+	"crypto/hmac"
+	"crypto/rsa"
+	"errors"
+	"hash"
+	"time"
+)
+
+type clientHandshakeStateTLS13 struct {
+	c           *Conn
+	ctx         context.Context
+	serverHello *serverHelloMsg
+	hello       *clientHelloMsg
+	ecdheKey    *ecdh.PrivateKey
+
+	session     *sessionState
+	earlySecret []byte
+	binderKey   []byte
+
+	certReq       *certificateRequestMsgTLS13
+	usingPSK      bool
+	sentDummyCCS  bool
+	suite         *cipherSuiteTLS13
+	transcript    hash.Hash
+	masterSecret  []byte
+	trafficSecret []byte // client_application_traffic_secret_0
+}
+
+// handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheKey, 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.ecdheKey == nil || len(hs.hello.keyShares) != 1 {
+		return c.sendAlert(alertInternalError)
+	}
+
+	if err := hs.checkServerHelloOrHRR(); err != nil {
+		return err
+	}
+
+	hs.transcript = hs.suite.hash.New()
+
+	if err := transcriptMsg(hs.hello, hs.transcript); err != nil {
+		return err
+	}
+
+	if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
+		if err := hs.sendDummyChangeCipherSpec(); err != nil {
+			return err
+		}
+		if err := hs.processHelloRetryRequest(); err != nil {
+			return err
+		}
+	}
+
+	if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
+		return err
+	}
+
+	c.buffering = true
+	if err := hs.processServerHello(); err != nil {
+		return err
+	}
+	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 := c.flush(); err != nil {
+		return err
+	}
+
+	c.isHandshakeComplete.Store(true)
+
+	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.extendedMasterSecret ||
+		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.c.quic != nil {
+		return nil
+	}
+	if hs.sentDummyCCS {
+		return nil
+	}
+	hs.sentDummyCCS = true
+
+	return hs.c.writeChangeCipherRecord()
+}
+
+// processHelloRetryRequest handles the HRR in hs.serverHello, modifies and
+// resends hs.hello, and reads the new ServerHello into hs.serverHello.
+func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
+	c := hs.c
+
+	// The first ClientHello gets double-hashed into the transcript upon a
+	// HelloRetryRequest. (The idea is that the server might offload transcript
+	// storage to the client in the cookie.) See RFC 8446, Section 4.4.1.
+	chHash := hs.transcript.Sum(nil)
+	hs.transcript.Reset()
+	hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+	hs.transcript.Write(chHash)
+	if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
+		return err
+	}
+
+	// The only HelloRetryRequest extensions we support are key_share and
+	// cookie, and clients must abort the handshake if the HRR would not result
+	// in any change in the ClientHello.
+	if hs.serverHello.selectedGroup == 0 && hs.serverHello.cookie == nil {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
+	}
+
+	if hs.serverHello.cookie != nil {
+		hs.hello.cookie = hs.serverHello.cookie
+	}
+
+	if hs.serverHello.serverShare.group != 0 {
+		c.sendAlert(alertDecodeError)
+		return errors.New("tls: received malformed key_share extension")
+	}
+
+	// If the server sent a key_share extension selecting a group, ensure it's
+	// a group we advertised but did not send a key share for, and send a key
+	// share for it this time.
+	if curveID := hs.serverHello.selectedGroup; curveID != 0 {
+		curveOK := false
+		for _, id := range hs.hello.supportedCurves {
+			if id == curveID {
+				curveOK = true
+				break
+			}
+		}
+		if !curveOK {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: server selected unsupported group")
+		}
+		if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); sentID == curveID {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
+		}
+		if _, ok := curveForCurveID(curveID); !ok {
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: CurvePreferences includes unsupported curve")
+		}
+		key, err := generateECDHEKey(c.config.rand(), curveID)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		hs.ecdheKey = key
+		hs.hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}}
+	}
+
+	hs.hello.raw = nil
+	if len(hs.hello.pskIdentities) > 0 {
+		pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
+		if pskSuite == nil {
+			return c.sendAlert(alertInternalError)
+		}
+		if pskSuite.hash == hs.suite.hash {
+			// Update binders and obfuscated_ticket_age.
+			ticketAge := c.config.time().Sub(time.Unix(int64(hs.session.createdAt), 0))
+			hs.hello.pskIdentities[0].obfuscatedTicketAge = uint32(ticketAge/time.Millisecond) + hs.session.ageAdd
+
+			transcript := hs.suite.hash.New()
+			transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+			transcript.Write(chHash)
+			if err := transcriptMsg(hs.serverHello, transcript); err != nil {
+				return err
+			}
+			helloBytes, err := hs.hello.marshalWithoutBinders()
+			if err != nil {
+				return err
+			}
+			transcript.Write(helloBytes)
+			pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)}
+			if err := hs.hello.updateBinders(pskBinders); err != nil {
+				return err
+			}
+		} else {
+			// Server selected a cipher suite incompatible with the PSK.
+			hs.hello.pskIdentities = nil
+			hs.hello.pskBinders = nil
+		}
+	}
+
+	if hs.hello.earlyData {
+		hs.hello.earlyData = false
+		c.quicRejectedEarlyData()
+	}
+
+	if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
+		return err
+	}
+
+	// serverHelloMsg is not included in the transcript
+	msg, err := c.readHandshake(nil)
+	if err != nil {
+		return err
+	}
+
+	serverHello, ok := msg.(*serverHelloMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(serverHello, msg)
+	}
+	hs.serverHello = serverHello
+
+	if err := hs.checkServerHelloOrHRR(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) processServerHello() error {
+	c := hs.c
+
+	if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
+		c.sendAlert(alertUnexpectedMessage)
+		return errors.New("tls: server sent two HelloRetryRequest messages")
+	}
+
+	if len(hs.serverHello.cookie) != 0 {
+		c.sendAlert(alertUnsupportedExtension)
+		return errors.New("tls: server sent a cookie in a normal ServerHello")
+	}
+
+	if hs.serverHello.selectedGroup != 0 {
+		c.sendAlert(alertDecodeError)
+		return errors.New("tls: malformed key_share extension")
+	}
+
+	if hs.serverHello.serverShare.group == 0 {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: server did not send a key share")
+	}
+	if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); hs.serverHello.serverShare.group != sentID {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: server selected unsupported group")
+	}
+
+	if !hs.serverHello.selectedIdentityPresent {
+		return nil
+	}
+
+	if int(hs.serverHello.selectedIdentity) >= len(hs.hello.pskIdentities) {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: server selected an invalid PSK")
+	}
+
+	if len(hs.hello.pskIdentities) != 1 || hs.session == nil {
+		return c.sendAlert(alertInternalError)
+	}
+	pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
+	if pskSuite == nil {
+		return c.sendAlert(alertInternalError)
+	}
+	if pskSuite.hash != hs.suite.hash {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: server selected an invalid PSK and cipher suite pair")
+	}
+
+	hs.usingPSK = true
+	c.didResume = true
+	c.peerCertificates = hs.session.peerCertificates
+	c.activeCertHandles = hs.session.activeCertHandles
+	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
+
+	peerKey, err := hs.ecdheKey.Curve().NewPublicKey(hs.serverHello.serverShare.data)
+	if err != nil {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: invalid server key share")
+	}
+	sharedKey, err := hs.ecdheKey.ECDH(peerKey)
+	if err != nil {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: invalid server key share")
+	}
+
+	earlySecret := hs.earlySecret
+	if !hs.usingPSK {
+		earlySecret = hs.suite.extract(nil, nil)
+	}
+
+	handshakeSecret := hs.suite.extract(sharedKey,
+		hs.suite.deriveSecret(earlySecret, "derived", nil))
+
+	clientSecret := hs.suite.deriveSecret(handshakeSecret,
+		clientHandshakeTrafficLabel, hs.transcript)
+	c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
+	serverSecret := hs.suite.deriveSecret(handshakeSecret,
+		serverHandshakeTrafficLabel, hs.transcript)
+	c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
+
+	if c.quic != nil {
+		if c.hand.Len() != 0 {
+			c.sendAlert(alertUnexpectedMessage)
+		}
+		c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret)
+		c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret)
+	}
+
+	err = c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+	err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.hello.random, serverSecret)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+
+	hs.masterSecret = hs.suite.extract(nil,
+		hs.suite.deriveSecret(handshakeSecret, "derived", nil))
+
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerParameters() error {
+	c := hs.c
+
+	msg, err := c.readHandshake(hs.transcript)
+	if err != nil {
+		return err
+	}
+
+	encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(encryptedExtensions, msg)
+	}
+
+	if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol, c.quic != nil); err != nil {
+		// RFC 8446 specifies that no_application_protocol is sent by servers, but
+		// does not specify how clients handle the selection of an incompatible protocol.
+		// RFC 9001 Section 8.1 specifies that QUIC clients send no_application_protocol
+		// in this case. Always sending no_application_protocol seems reasonable.
+		c.sendAlert(alertNoApplicationProtocol)
+		return err
+	}
+	c.clientProtocol = encryptedExtensions.alpnProtocol
+
+	if c.quic != nil {
+		if encryptedExtensions.quicTransportParameters == nil {
+			// RFC 9001 Section 8.2.
+			c.sendAlert(alertMissingExtension)
+			return errors.New("tls: server did not send a quic_transport_parameters extension")
+		}
+		c.quicSetTransportParameters(encryptedExtensions.quicTransportParameters)
+	} else {
+		if encryptedExtensions.quicTransportParameters != nil {
+			c.sendAlert(alertUnsupportedExtension)
+			return errors.New("tls: server sent an unexpected quic_transport_parameters extension")
+		}
+	}
+
+	if !hs.hello.earlyData && encryptedExtensions.earlyData {
+		c.sendAlert(alertUnsupportedExtension)
+		return errors.New("tls: server sent an unexpected early_data extension")
+	}
+	if hs.hello.earlyData && !encryptedExtensions.earlyData {
+		c.quicRejectedEarlyData()
+	}
+	if encryptedExtensions.earlyData {
+		if hs.session.cipherSuite != c.cipherSuite {
+			c.sendAlert(alertHandshakeFailure)
+			return errors.New("tls: server accepted 0-RTT with the wrong cipher suite")
+		}
+		if hs.session.alpnProtocol != c.clientProtocol {
+			c.sendAlert(alertHandshakeFailure)
+			return errors.New("tls: server accepted 0-RTT with the wrong ALPN")
+		}
+	}
+
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
+	c := hs.c
+
+	// Either a PSK or a certificate is always used, but not both.
+	// See RFC 8446, Section 4.1.1.
+	if hs.usingPSK {
+		// Make sure the connection is still being verified whether or not this
+		// is a resumption. Resumptions currently don't reverify certificates so
+		// they don't call verifyServerCertificate. See Issue 31641.
+		if c.config.VerifyConnection != nil {
+			if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+				c.sendAlert(alertBadCertificate)
+				return err
+			}
+		}
+		return nil
+	}
+
+	msg, err := c.readHandshake(hs.transcript)
+	if err != nil {
+		return err
+	}
+
+	certReq, ok := msg.(*certificateRequestMsgTLS13)
+	if ok {
+		hs.certReq = certReq
+
+		msg, err = c.readHandshake(hs.transcript)
+		if err != nil {
+			return err
+		}
+	}
+
+	certMsg, ok := msg.(*certificateMsgTLS13)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certMsg, msg)
+	}
+	if len(certMsg.certificate.Certificate) == 0 {
+		c.sendAlert(alertDecodeError)
+		return errors.New("tls: received empty certificates message")
+	}
+
+	c.scts = certMsg.certificate.SignedCertificateTimestamps
+	c.ocspResponse = certMsg.certificate.OCSPStaple
+
+	if err := c.verifyServerCertificate(certMsg.certificate.Certificate); err != nil {
+		return err
+	}
+
+	// certificateVerifyMsg is included in the transcript, but not until
+	// after we verify the handshake signature, since the state before
+	// this message was sent is used.
+	msg, err = c.readHandshake(nil)
+	if err != nil {
+		return err
+	}
+
+	certVerify, ok := msg.(*certificateVerifyMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certVerify, msg)
+	}
+
+	// See RFC 8446, Section 4.4.3.
+	if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: certificate used with invalid signature algorithm")
+	}
+	sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
+	if err != nil {
+		return c.sendAlert(alertInternalError)
+	}
+	if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: certificate used with invalid signature algorithm")
+	}
+	signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
+	if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
+		sigHash, signed, certVerify.signature); err != nil {
+		c.sendAlert(alertDecryptError)
+		return errors.New("tls: invalid signature by the server certificate: " + err.Error())
+	}
+
+	if err := transcriptMsg(certVerify, hs.transcript); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerFinished() error {
+	c := hs.c
+
+	// finishedMsg is included in the transcript, but not until after we
+	// check the client version, since the state before this message was
+	// sent is used during verification.
+	msg, err := c.readHandshake(nil)
+	if err != nil {
+		return err
+	}
+
+	finished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(finished, msg)
+	}
+
+	expectedMAC := hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
+	if !hmac.Equal(expectedMAC, finished.verifyData) {
+		c.sendAlert(alertDecryptError)
+		return errors.New("tls: invalid server finished hash")
+	}
+
+	if err := transcriptMsg(finished, hs.transcript); err != nil {
+		return err
+	}
+
+	// Derive secrets that take context through the server Finished.
+
+	hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
+		clientApplicationTrafficLabel, hs.transcript)
+	serverSecret := hs.suite.deriveSecret(hs.masterSecret,
+		serverApplicationTrafficLabel, hs.transcript)
+	c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
+
+	err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+	err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.hello.random, serverSecret)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+
+	c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
+
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
+	c := hs.c
+
+	if hs.certReq == nil {
+		return nil
+	}
+
+	cert, err := c.getClientCertificate(toCertificateRequestInfo(&certificateRequestInfo{
+		AcceptableCAs:    hs.certReq.certificateAuthorities,
+		SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
+		Version:          c.vers,
+		ctx:              hs.ctx,
+	}))
+	if err != nil {
+		return err
+	}
+
+	certMsg := new(certificateMsgTLS13)
+
+	certMsg.certificate = *cert
+	certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0
+	certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0
+
+	if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
+		return err
+	}
+
+	// If we sent an empty certificate message, skip the CertificateVerify.
+	if len(cert.Certificate) == 0 {
+		return nil
+	}
+
+	certVerifyMsg := new(certificateVerifyMsg)
+	certVerifyMsg.hasSignatureAlgorithm = true
+
+	certVerifyMsg.signatureAlgorithm, err = selectSignatureScheme(c.vers, cert, hs.certReq.supportedSignatureAlgorithms)
+	if err != nil {
+		// getClientCertificate returned a certificate incompatible with the
+		// CertificateRequestInfo supported signature algorithms.
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+
+	sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
+	if err != nil {
+		return c.sendAlert(alertInternalError)
+	}
+
+	signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
+	signOpts := crypto.SignerOpts(sigHash)
+	if sigType == signatureRSAPSS {
+		signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+	}
+	sig, err := cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: failed to sign handshake: " + err.Error())
+	}
+	certVerifyMsg.signature = sig
+
+	if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
+	c := hs.c
+
+	finished := &finishedMsg{
+		verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
+	}
+
+	if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
+		return err
+	}
+
+	c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
+
+	if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil {
+		c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
+			resumptionLabel, hs.transcript)
+	}
+
+	if c.quic != nil {
+		if c.hand.Len() != 0 {
+			c.sendAlert(alertUnexpectedMessage)
+		}
+		c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, hs.trafficSecret)
+	}
+
+	return nil
+}
+
+func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
+	if !c.isClient {
+		c.sendAlert(alertUnexpectedMessage)
+		return errors.New("tls: received new session ticket from a client")
+	}
+
+	if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
+		return nil
+	}
+
+	// See RFC 8446, Section 4.6.1.
+	if msg.lifetime == 0 {
+		return nil
+	}
+	lifetime := time.Duration(msg.lifetime) * time.Second
+	if lifetime > maxSessionTicketLifetime {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: received a session ticket with invalid lifetime")
+	}
+
+	// RFC 9001, Section 4.6.1
+	if c.quic != nil && msg.maxEarlyData != 0 && msg.maxEarlyData != 0xffffffff {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: invalid early data for QUIC connection")
+	}
+
+	cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
+	if cipherSuite == nil || c.resumptionSecret == nil {
+		return c.sendAlert(alertInternalError)
+	}
+
+	psk := cipherSuite.expandLabel(c.resumptionSecret, "resumption",
+		msg.nonce, cipherSuite.hash.Size())
+
+	session, err := c.sessionState()
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+	session.secret = psk
+	session.useBy = uint64(c.config.time().Add(lifetime).Unix())
+	session.ageAdd = msg.ageAdd
+	session.EarlyData = c.quic != nil && msg.maxEarlyData == 0xffffffff // RFC 9001, Section 4.6.1
+	cs := &clientSessionState{ticket: msg.label, session: session}
+
+	if cacheKey := c.clientSessionCacheKey(); cacheKey != "" {
+		c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(cs))
+	}
+
+	return nil
+}

+ 2267 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_messages.go

@@ -0,0 +1,2267 @@
+// 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 (
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
+	"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
+	secureRenegotiationSupported     bool
+	secureRenegotiation              []byte
+	extendedMasterSecret             bool
+	alpnProtocols                    []string
+	scts                             bool
+	supportedVersions                []uint16
+	cookie                           []byte
+	keyShares                        []keyShare
+	earlyData                        bool
+	pskModes                         []uint8
+	pskIdentities                    []pskIdentity
+	pskBinders                       [][]byte
+	quicTransportParameters          []byte
+
+	// [Psiphon]
+	PRNG *prng.PRNG
+}
+
+func (m *clientHelloMsg) marshal() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	// [Psiphon]
+	// Randomize the Client Hello.
+	if m.PRNG != nil {
+		return m.marshalRandomized(), nil
+	}
+
+	var exts cryptobyte.Builder
+	if len(m.serverName) > 0 {
+		// RFC 6066, Section 3
+		exts.AddUint16(extensionServerName)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddUint8(0) // name_type = host_name
+				exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+					exts.AddBytes([]byte(m.serverName))
+				})
+			})
+		})
+	}
+	if m.ocspStapling {
+		// RFC 4366, Section 3.6
+		exts.AddUint16(extensionStatusRequest)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint8(1)  // status_type = ocsp
+			exts.AddUint16(0) // empty responder_id_list
+			exts.AddUint16(0) // empty request_extensions
+		})
+	}
+	if len(m.supportedCurves) > 0 {
+		// RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
+		exts.AddUint16(extensionSupportedCurves)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				for _, curve := range m.supportedCurves {
+					exts.AddUint16(uint16(curve))
+				}
+			})
+		})
+	}
+	if len(m.supportedPoints) > 0 {
+		// RFC 4492, Section 5.1.2
+		exts.AddUint16(extensionSupportedPoints)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddBytes(m.supportedPoints)
+			})
+		})
+	}
+	if m.ticketSupported {
+		// RFC 5077, Section 3.2
+		exts.AddUint16(extensionSessionTicket)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddBytes(m.sessionTicket)
+		})
+	}
+	if len(m.supportedSignatureAlgorithms) > 0 {
+		// RFC 5246, Section 7.4.1.4.1
+		exts.AddUint16(extensionSignatureAlgorithms)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				for _, sigAlgo := range m.supportedSignatureAlgorithms {
+					exts.AddUint16(uint16(sigAlgo))
+				}
+			})
+		})
+	}
+	if len(m.supportedSignatureAlgorithmsCert) > 0 {
+		// RFC 8446, Section 4.2.3
+		exts.AddUint16(extensionSignatureAlgorithmsCert)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
+					exts.AddUint16(uint16(sigAlgo))
+				}
+			})
+		})
+	}
+	if m.secureRenegotiationSupported {
+		// RFC 5746, Section 3.2
+		exts.AddUint16(extensionRenegotiationInfo)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddBytes(m.secureRenegotiation)
+			})
+		})
+	}
+	if m.extendedMasterSecret {
+		// RFC 7627
+		exts.AddUint16(extensionExtendedMasterSecret)
+		exts.AddUint16(0) // empty extension_data
+	}
+	if len(m.alpnProtocols) > 0 {
+		// RFC 7301, Section 3.1
+		exts.AddUint16(extensionALPN)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				for _, proto := range m.alpnProtocols {
+					exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+						exts.AddBytes([]byte(proto))
+					})
+				}
+			})
+		})
+	}
+	if m.scts {
+		// RFC 6962, Section 3.3.1
+		exts.AddUint16(extensionSCT)
+		exts.AddUint16(0) // empty extension_data
+	}
+	if len(m.supportedVersions) > 0 {
+		// RFC 8446, Section 4.2.1
+		exts.AddUint16(extensionSupportedVersions)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+				for _, vers := range m.supportedVersions {
+					exts.AddUint16(vers)
+				}
+			})
+		})
+	}
+	if len(m.cookie) > 0 {
+		// RFC 8446, Section 4.2.2
+		exts.AddUint16(extensionCookie)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddBytes(m.cookie)
+			})
+		})
+	}
+	if len(m.keyShares) > 0 {
+		// RFC 8446, Section 4.2.8
+		exts.AddUint16(extensionKeyShare)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				for _, ks := range m.keyShares {
+					exts.AddUint16(uint16(ks.group))
+					exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+						exts.AddBytes(ks.data)
+					})
+				}
+			})
+		})
+	}
+	if m.earlyData {
+		// RFC 8446, Section 4.2.10
+		exts.AddUint16(extensionEarlyData)
+		exts.AddUint16(0) // empty extension_data
+	}
+	if len(m.pskModes) > 0 {
+		// RFC 8446, Section 4.2.9
+		exts.AddUint16(extensionPSKModes)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddBytes(m.pskModes)
+			})
+		})
+	}
+	if m.quicTransportParameters != nil { // marshal zero-length parameters when present
+		// RFC 9001, Section 8.2
+		exts.AddUint16(extensionQUICTransportParameters)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddBytes(m.quicTransportParameters)
+		})
+	}
+	if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
+		// RFC 8446, Section 4.2.11
+		exts.AddUint16(extensionPreSharedKey)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				for _, psk := range m.pskIdentities {
+					exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+						exts.AddBytes(psk.label)
+					})
+					exts.AddUint32(psk.obfuscatedTicketAge)
+				}
+			})
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				for _, binder := range m.pskBinders {
+					exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+						exts.AddBytes(binder)
+					})
+				}
+			})
+		})
+	}
+	extBytes, err := exts.Bytes()
+	if err != nil {
+		return nil, err
+	}
+
+	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 len(extBytes) > 0 {
+			b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+				b.AddBytes(extBytes)
+			})
+		}
+	})
+
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+// [Psiphon]
+//
+// marshalRandomized is a randomized variant of marshal. The original Marshal
+// is retained as-is to ease future merging.
+//
+// The offered cipher suites and algorithms are shuffled and truncated. Longer
+// lists are selected with higher probability. Extensions are shuffled.
+//
+// The quic_transport_parameters extension is marshaled in quic-go and is
+// randomized in TransportParameters.Marshal.
+func (m *clientHelloMsg) marshalRandomized() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
+
+	// Some inputs, such as m.supportedCurves, point to global variables. Copy
+	// all slices before truncating.
+
+	cipherSuites := make([]uint16, len(m.cipherSuites))
+	for {
+		perm := m.PRNG.Perm(len(m.cipherSuites))
+		for i, j := range perm {
+			cipherSuites[j] = m.cipherSuites[i]
+		}
+		cut := len(cipherSuites)
+		for ; cut > 1; cut-- {
+			if !m.PRNG.FlipCoin() {
+				break
+			}
+		}
+
+		// Must contain at least one of defaultCipherSuitesTLS13.
+		containsDefault := false
+		for _, suite := range cipherSuites[:cut] {
+			for _, defaultSuite := range defaultCipherSuitesTLS13 {
+				if suite == defaultSuite {
+					containsDefault = true
+					break
+				}
+			}
+			if containsDefault {
+				break
+			}
+		}
+		if containsDefault {
+			cipherSuites = cipherSuites[:cut]
+			break
+		}
+	}
+
+	compressionMethods := make([]uint8, len(m.compressionMethods))
+	perm := m.PRNG.Perm(len(m.compressionMethods))
+	for i, j := range perm {
+		compressionMethods[j] = m.compressionMethods[i]
+	}
+	cut := len(compressionMethods)
+	for ; cut > 1; cut-- {
+		if !m.PRNG.FlipCoin() {
+			break
+		}
+	}
+	compressionMethods = compressionMethods[:cut]
+
+	supportedCurves := make([]CurveID, len(m.supportedCurves))
+	perm = m.PRNG.Perm(len(m.supportedCurves))
+	for i, j := range perm {
+		supportedCurves[j] = m.supportedCurves[i]
+	}
+	cut = len(supportedCurves)
+	for ; cut > 1; cut-- {
+		if !m.PRNG.FlipCoin() {
+			break
+		}
+	}
+	supportedCurves = supportedCurves[:cut]
+
+	supportedPoints := make([]uint8, len(m.supportedPoints))
+	perm = m.PRNG.Perm(len(m.supportedPoints))
+	for i, j := range perm {
+		supportedPoints[j] = m.supportedPoints[i]
+	}
+	cut = len(supportedPoints)
+	for ; cut > 1; cut-- {
+		if !m.PRNG.FlipCoin() {
+			break
+		}
+	}
+	supportedPoints = supportedPoints[:cut]
+
+	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 cipherSuites {
+				b.AddUint16(suite)
+			}
+		})
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes(compressionMethods)
+		})
+
+		// If extensions aren't present, omit them.
+		var extensionsPresent bool
+		bWithoutExtensions := *b
+
+		b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+
+			extensionMarshallers := []func(){
+
+				func() {
+					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))
+								})
+							})
+						})
+					}
+				},
+
+				func() {
+					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
+						})
+					}
+				},
+
+				func() {
+					if len(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 supportedCurves {
+									b.AddUint16(uint16(curve))
+								}
+							})
+						})
+					}
+				},
+
+				func() {
+					if len(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(supportedPoints)
+							})
+						})
+					}
+				},
+
+				func() {
+					if m.ticketSupported {
+						// RFC 5077, Section 3.2
+						b.AddUint16(extensionSessionTicket)
+						b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+							b.AddBytes(m.sessionTicket)
+						})
+					}
+				},
+
+				func() {
+					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))
+								}
+							})
+						})
+					}
+				},
+
+				func() {
+					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))
+								}
+							})
+						})
+					}
+				},
+
+				func() {
+					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)
+							})
+						})
+					}
+				},
+
+				func() {
+					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))
+									})
+								}
+							})
+						})
+					}
+				},
+
+				func() {
+					if m.scts {
+						// RFC 6962, Section 3.3.1
+						b.AddUint16(extensionSCT)
+						b.AddUint16(0) // empty extension_data
+					}
+				},
+
+				func() {
+					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)
+								}
+							})
+						})
+					}
+				},
+
+				func() {
+					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)
+							})
+						})
+					}
+				},
+
+				func() {
+					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)
+									})
+								}
+							})
+						})
+					}
+				},
+
+				func() {
+					if m.earlyData {
+						// RFC 8446, Section 4.2.10
+						b.AddUint16(extensionEarlyData)
+						b.AddUint16(0) // empty extension_data
+					}
+				},
+
+				func() {
+					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)
+							})
+						})
+					}
+				},
+
+				func() {
+					if m.quicTransportParameters != nil { // marshal zero-length parameters when present
+						// RFC 9001, Section 8.2
+						b.AddUint16(extensionQUICTransportParameters)
+						b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+							b.AddBytes(m.quicTransportParameters)
+						})
+					}
+				},
+			}
+
+			perm = m.PRNG.Perm(len(extensionMarshallers))
+			for _, j := range perm {
+				extensionMarshallers[j]()
+			}
+
+			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, error) {
+	bindersLen := 2 // uint16 length prefix
+	for _, binder := range m.pskBinders {
+		bindersLen += 1 // uint8 length prefix
+		bindersLen += len(binder)
+	}
+
+	fullMessage, err := m.marshal()
+	if err != nil {
+		return nil, err
+	}
+	return fullMessage[:len(fullMessage)-bindersLen], nil
+}
+
+// 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) error {
+	if len(pskBinders) != len(m.pskBinders) {
+		return errors.New("tls: internal error: pskBinders length mismatch")
+	}
+	for i := range m.pskBinders {
+		if len(pskBinders[i]) != len(m.pskBinders[i]) {
+			return errors.New("tls: internal error: pskBinders length mismatch")
+		}
+	}
+	m.pskBinders = pskBinders
+	if m.raw != nil {
+		helloBytes, err := m.marshalWithoutBinders()
+		if err != nil {
+			return err
+		}
+		lenWithoutBinders := len(helloBytes)
+		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) {
+			return errors.New("tls: internal error: failed to update binders")
+		}
+	}
+
+	return nil
+}
+
+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
+	}
+
+	seenExts := make(map[uint16]bool)
+	for !extensions.Empty() {
+		var extension uint16
+		var extData cryptobyte.String
+		if !extensions.ReadUint16(&extension) ||
+			!extensions.ReadUint16LengthPrefixed(&extData) {
+			return false
+		}
+
+		if seenExts[extension] {
+			return false
+		}
+		seenExts[extension] = true
+
+		switch extension {
+		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 extensionExtendedMasterSecret:
+			// RFC 7627
+			m.extendedMasterSecret = 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 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 extensionQUICTransportParameters:
+			m.quicTransportParameters = make([]byte, len(extData))
+			if !extData.CopyBytes(m.quicTransportParameters) {
+				return false
+			}
+		case extensionPreSharedKey:
+			// RFC 8446, Section 4.2.11
+			if !extensions.Empty() {
+				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
+	extendedMasterSecret         bool
+	alpnProtocol                 string
+	scts                         [][]byte
+	supportedVersion             uint16
+	serverShare                  keyShare
+	selectedIdentityPresent      bool
+	selectedIdentity             uint16
+	supportedPoints              []uint8
+
+	// HelloRetryRequest extensions
+	cookie        []byte
+	selectedGroup CurveID
+}
+
+func (m *serverHelloMsg) marshal() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	var exts cryptobyte.Builder
+	if m.ocspStapling {
+		exts.AddUint16(extensionStatusRequest)
+		exts.AddUint16(0) // empty extension_data
+	}
+	if m.ticketSupported {
+		exts.AddUint16(extensionSessionTicket)
+		exts.AddUint16(0) // empty extension_data
+	}
+	if m.secureRenegotiationSupported {
+		exts.AddUint16(extensionRenegotiationInfo)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddBytes(m.secureRenegotiation)
+			})
+		})
+	}
+	if m.extendedMasterSecret {
+		exts.AddUint16(extensionExtendedMasterSecret)
+		exts.AddUint16(0) // empty extension_data
+	}
+	if len(m.alpnProtocol) > 0 {
+		exts.AddUint16(extensionALPN)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+					exts.AddBytes([]byte(m.alpnProtocol))
+				})
+			})
+		})
+	}
+	if len(m.scts) > 0 {
+		exts.AddUint16(extensionSCT)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				for _, sct := range m.scts {
+					exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+						exts.AddBytes(sct)
+					})
+				}
+			})
+		})
+	}
+	if m.supportedVersion != 0 {
+		exts.AddUint16(extensionSupportedVersions)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16(m.supportedVersion)
+		})
+	}
+	if m.serverShare.group != 0 {
+		exts.AddUint16(extensionKeyShare)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16(uint16(m.serverShare.group))
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddBytes(m.serverShare.data)
+			})
+		})
+	}
+	if m.selectedIdentityPresent {
+		exts.AddUint16(extensionPreSharedKey)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16(m.selectedIdentity)
+		})
+	}
+
+	if len(m.cookie) > 0 {
+		exts.AddUint16(extensionCookie)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddBytes(m.cookie)
+			})
+		})
+	}
+	if m.selectedGroup != 0 {
+		exts.AddUint16(extensionKeyShare)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint16(uint16(m.selectedGroup))
+		})
+	}
+	if len(m.supportedPoints) > 0 {
+		exts.AddUint16(extensionSupportedPoints)
+		exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+			exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+				exts.AddBytes(m.supportedPoints)
+			})
+		})
+	}
+
+	extBytes, err := exts.Bytes()
+	if err != nil {
+		return nil, err
+	}
+
+	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 len(extBytes) > 0 {
+			b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+				b.AddBytes(extBytes)
+			})
+		}
+	})
+
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+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
+	}
+
+	seenExts := make(map[uint16]bool)
+	for !extensions.Empty() {
+		var extension uint16
+		var extData cryptobyte.String
+		if !extensions.ReadUint16(&extension) ||
+			!extensions.ReadUint16LengthPrefixed(&extData) {
+			return false
+		}
+
+		if seenExts[extension] {
+			return false
+		}
+		seenExts[extension] = true
+
+		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 extensionExtendedMasterSecret:
+			m.extendedMasterSecret = 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
+			}
+		default:
+			// Ignore unknown extensions.
+			continue
+		}
+
+		if !extData.Empty() {
+			return false
+		}
+	}
+
+	return true
+}
+
+type encryptedExtensionsMsg struct {
+	raw                     []byte
+	alpnProtocol            string
+	quicTransportParameters []byte
+	earlyData               bool
+}
+
+func (m *encryptedExtensionsMsg) marshal() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	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 m.quicTransportParameters != nil { // marshal zero-length parameters when present
+				// draft-ietf-quic-tls-32, Section 8.2
+				b.AddUint16(extensionQUICTransportParameters)
+				b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+					b.AddBytes(m.quicTransportParameters)
+				})
+			}
+			if m.earlyData {
+				// RFC 8446, Section 4.2.10
+				b.AddUint16(extensionEarlyData)
+				b.AddUint16(0) // empty extension_data
+			}
+		})
+	})
+
+	var err error
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+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 extensionQUICTransportParameters:
+			m.quicTransportParameters = make([]byte, len(extData))
+			if !extData.CopyBytes(m.quicTransportParameters) {
+				return false
+			}
+		case extensionEarlyData:
+			// RFC 8446, Section 4.2.10
+			m.earlyData = true
+		default:
+			// Ignore unknown extensions.
+			continue
+		}
+
+		if !extData.Empty() {
+			return false
+		}
+	}
+
+	return true
+}
+
+type endOfEarlyDataMsg struct{}
+
+func (m *endOfEarlyDataMsg) marshal() ([]byte, error) {
+	x := make([]byte, 4)
+	x[0] = typeEndOfEarlyData
+	return x, nil
+}
+
+func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}
+
+type keyUpdateMsg struct {
+	raw             []byte
+	updateRequested bool
+}
+
+func (m *keyUpdateMsg) marshal() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeKeyUpdate)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		if m.updateRequested {
+			b.AddUint8(1)
+		} else {
+			b.AddUint8(0)
+		}
+	})
+
+	var err error
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+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, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	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)
+				})
+			}
+		})
+	})
+
+	var err error
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+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
+	supportedSignatureAlgorithms     []SignatureScheme
+	supportedSignatureAlgorithmsCert []SignatureScheme
+	certificateAuthorities           [][]byte
+}
+
+func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	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 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)
+							})
+						}
+					})
+				})
+			}
+		})
+	})
+
+	var err error
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+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 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() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	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 m.raw, nil
+}
+
+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
+}
+
+func (m *certificateMsgTLS13) marshal() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	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
+		}
+		marshalCertificate(b, certificate)
+	})
+
+	var err error
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+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 and SCT for leaf certificates.
+					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)
+								})
+							}
+						})
+					})
+				}
+			})
+		}
+	})
+}
+
+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
+
+	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)
+				}
+			default:
+				// Ignore unknown extensions.
+				continue
+			}
+
+			if !extData.Empty() {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+type serverKeyExchangeMsg struct {
+	raw []byte
+	key []byte
+}
+
+func (m *serverKeyExchangeMsg) marshal() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+	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, nil
+}
+
+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, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	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)
+		})
+	})
+
+	var err error
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+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, error) {
+	x := make([]byte, 4)
+	x[0] = typeServerHelloDone
+	return x, nil
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}
+
+type clientKeyExchangeMsg struct {
+	raw        []byte
+	ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) marshal() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+	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, nil
+}
+
+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, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	var b cryptobyte.Builder
+	b.AddUint8(typeFinished)
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(m.verifyData)
+	})
+
+	var err error
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+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() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	// 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 m.raw, nil
+}
+
+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() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	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)
+		})
+	})
+
+	var err error
+	m.raw, err = b.Bytes()
+	return m.raw, err
+}
+
+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() ([]byte, error) {
+	if m.raw != nil {
+		return m.raw, nil
+	}
+
+	// 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 m.raw, nil
+}
+
+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, error) {
+	return []byte{typeHelloRequest, 0, 0, 0}, nil
+}
+
+func (*helloRequestMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}
+
+type transcriptHash interface {
+	Write([]byte) (int, error)
+}
+
+// transcriptMsg is a helper used to marshal and hash messages which typically
+// are not written to the wire, and as such aren't hashed during Conn.writeRecord.
+func transcriptMsg(msg handshakeMessage, h transcriptHash) error {
+	data, err := msg.marshal()
+	if err != nil {
+		return err
+	}
+	h.Write(data)
+	return nil
+}

+ 955 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_server.go

@@ -0,0 +1,955 @@
+// 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"
+	"time"
+)
+
+// serverHandshakeState contains details of a server handshake in progress.
+// It's discarded once the handshake has completed.
+type serverHandshakeState struct {
+	c            *Conn
+	ctx          context.Context
+	clientHello  *clientHelloMsg
+	hello        *serverHelloMsg
+	suite        *cipherSuite
+	ecdheOk      bool
+	ecSignOk     bool
+	rsaDecryptOk bool
+	rsaSignOk    bool
+	sessionState *sessionState
+	finishedHash finishedHash
+	masterSecret []byte
+	cert         *Certificate
+}
+
+// serverHandshake performs a TLS handshake as a server.
+func (c *Conn) serverHandshake(ctx context.Context) error {
+	clientHello, err := c.readClientHello(ctx)
+	if err != nil {
+		return err
+	}
+
+	if c.vers == VersionTLS13 {
+		hs := serverHandshakeStateTLS13{
+			c:           c,
+			ctx:         ctx,
+			clientHello: clientHello,
+		}
+		return hs.handshake()
+	}
+
+	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 err := hs.checkForResumption(); err != nil {
+		return err
+	}
+	if hs.sessionState != nil {
+		// The client has included a session ticket and so we do an abbreviated handshake.
+		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)
+	c.isHandshakeComplete.Store(true)
+
+	return nil
+}
+
+// readClientHello reads a ClientHello message and selects the protocol version.
+func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
+	// clientHelloMsg is included in the transcript, but we haven't initialized
+	// it yet. The respective handshake functions will record it themselves.
+	msg, err := c.readHandshake(nil)
+	if err != nil {
+		return nil, err
+	}
+	clientHello, ok := msg.(*clientHelloMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return nil, unexpectedMessageError(clientHello, msg)
+	}
+
+	var configForClient *config
+	originalConfig := c.config
+	if c.config.GetConfigForClient != nil {
+		chi := newClientHelloInfo(ctx, c, clientHello)
+		if cfc, err := c.config.GetConfigForClient(chi); err != nil {
+			c.sendAlert(alertInternalError)
+			return nil, err
+		} else if cfc != nil {
+			configForClient = fromConfig(cfc)
+			c.config = configForClient
+		}
+	}
+	c.ticketKeys = originalConfig.ticketKeys(configForClient)
+
+	clientVersions := clientHello.supportedVersions
+	if len(clientHello.supportedVersions) == 0 {
+		clientVersions = supportedVersionsFromMax(clientHello.vers)
+	}
+	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.extendedMasterSecret = hs.clientHello.extendedMasterSecret
+	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, false)
+	if err != nil {
+		c.sendAlert(alertNoApplicationProtocol)
+		return err
+	}
+	hs.hello.alpnProtocol = selectedProto
+	c.clientProtocol = selectedProto
+
+	hs.cert, err = c.config.getCertificate(newClientHelloInfo(hs.ctx, c, hs.clientHello))
+	if err != nil {
+		if err == errNoCertificates {
+			c.sendAlert(alertUnrecognizedName)
+		} else {
+			c.sendAlert(alertInternalError)
+		}
+		return err
+	}
+	if hs.clientHello.scts {
+		hs.hello.scts = hs.cert.SignedCertificateTimestamps
+	}
+
+	hs.ecdheOk = supportsECDHE(c.config, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints)
+
+	if hs.ecdheOk && len(hs.clientHello.supportedPoints) > 0 {
+		// Although omitting the ec_point_formats extension is permitted, some
+		// old OpenSSL version will refuse to handshake if not present.
+		//
+		// Per RFC 4492, section 5.1.2, implementations MUST support the
+		// uncompressed point format. See golang.org/issue/31943.
+		hs.hello.supportedPoints = []uint8{pointFormatUncompressed}
+	}
+
+	if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
+		switch priv.Public().(type) {
+		case *ecdsa.PublicKey:
+			hs.ecSignOk = true
+		case ed25519.PublicKey:
+			hs.ecSignOk = true
+		case *rsa.PublicKey:
+			hs.rsaSignOk = true
+		default:
+			c.sendAlert(alertInternalError)
+			return fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
+		}
+	}
+	if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
+		switch priv.Public().(type) {
+		case *rsa.PublicKey:
+			hs.rsaDecryptOk = true
+		default:
+			c.sendAlert(alertInternalError)
+			return fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
+		}
+	}
+
+	return nil
+}
+
+// negotiateALPN picks a shared ALPN protocol that both sides support in server
+// preference order. If ALPN is not configured or the peer doesn't support it,
+// it returns "" and no error.
+func negotiateALPN(serverProtos, clientProtos []string, quic bool) (string, error) {
+	if len(serverProtos) == 0 || len(clientProtos) == 0 {
+		if quic && len(serverProtos) != 0 {
+			// RFC 9001, Section 8.1
+			return "", fmt.Errorf("tls: client did not request an application protocol")
+		}
+		return "", nil
+	}
+	var http11fallback bool
+	for _, s := range serverProtos {
+		for _, c := range clientProtos {
+			if s == c {
+				return s, nil
+			}
+			if s == "h2" && c == "http/1.1" {
+				http11fallback = true
+			}
+		}
+	}
+	// As a special case, let http/1.1 clients connect to h2 servers as if they
+	// didn't support ALPN. We used not to enforce protocol overlap, so over
+	// time a number of HTTP servers were configured with only "h2", but
+	// expected to accept connections from "http/1.1" clients. See Issue 46310.
+	if http11fallback {
+		return "", nil
+	}
+	return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", clientProtos)
+}
+
+// supportsECDHE returns whether ECDHE key exchanges can be used with this
+// pre-TLS 1.3 client.
+func supportsECDHE(c *config, supportedCurves []CurveID, supportedPoints []uint8) bool {
+	supportsCurve := false
+	for _, curve := range supportedCurves {
+		if c.supportsCurve(curve) {
+			supportsCurve = true
+			break
+		}
+	}
+
+	supportsPointFormat := false
+	for _, pointFormat := range supportedPoints {
+		if pointFormat == pointFormatUncompressed {
+			supportsPointFormat = true
+			break
+		}
+	}
+	// Per RFC 8422, Section 5.1.2, if the Supported Point Formats extension is
+	// missing, uncompressed points are supported. If supportedPoints is empty,
+	// the extension must be missing, as an empty extension body is rejected by
+	// the parser. See https://go.dev/issue/49126.
+	if len(supportedPoints) == 0 {
+		supportsPointFormat = true
+	}
+
+	return supportsCurve && supportsPointFormat
+}
+
+func (hs *serverHandshakeState) pickCipherSuite() error {
+	c := hs.c
+
+	preferenceOrder := cipherSuitesPreferenceOrder
+	if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
+		preferenceOrder = cipherSuitesPreferenceOrderNoAES
+	}
+
+	configCipherSuites := c.config.cipherSuites()
+	preferenceList := make([]uint16, 0, len(configCipherSuites))
+	for _, suiteID := range preferenceOrder {
+		for _, id := range configCipherSuites {
+			if id == suiteID {
+				preferenceList = append(preferenceList, id)
+				break
+			}
+		}
+	}
+
+	hs.suite = selectCipherSuite(preferenceList, hs.clientHello.cipherSuites, hs.cipherSuiteOk)
+	if hs.suite == nil {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: no cipher suite supported by both client and server")
+	}
+	c.cipherSuite = hs.suite.id
+
+	for _, id := range hs.clientHello.cipherSuites {
+		if id == TLS_FALLBACK_SCSV {
+			// The client is doing a fallback connection. See RFC 7507.
+			if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer) {
+				c.sendAlert(alertInappropriateFallback)
+				return errors.New("tls: client using inappropriate protocol fallback")
+			}
+			break
+		}
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeState) cipherSuiteOk(c *cipherSuite) bool {
+	if c.flags&suiteECDHE != 0 {
+		if !hs.ecdheOk {
+			return false
+		}
+		if c.flags&suiteECSign != 0 {
+			if !hs.ecSignOk {
+				return false
+			}
+		} else if !hs.rsaSignOk {
+			return false
+		}
+	} else if !hs.rsaDecryptOk {
+		return false
+	}
+	if hs.c.vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
+		return false
+	}
+	return true
+}
+
+// checkForResumption reports whether we should perform resumption on this connection.
+func (hs *serverHandshakeState) checkForResumption() error {
+	c := hs.c
+
+	if c.config.SessionTicketsDisabled {
+		return nil
+	}
+
+	var sessionState *sessionState
+	if c.config.UnwrapSession != nil {
+		ss, err := c.config.UnwrapSession(hs.clientHello.sessionTicket, c.connectionStateLocked())
+		if err != nil {
+			return err
+		}
+		if ss == nil {
+			return nil
+		}
+		sessionState = fromSessionState(ss)
+	} else {
+		plaintext := c.config.decryptTicket(hs.clientHello.sessionTicket, c.ticketKeys)
+		if plaintext == nil {
+			return nil
+		}
+		ss, err := ParseSessionState(plaintext)
+		if err != nil {
+			return nil
+		}
+		sessionState = ss
+	}
+
+	// TLS 1.2 tickets don't natively have a lifetime, but we want to avoid
+	// re-wrapping the same master secret in different tickets over and over for
+	// too long, weakening forward secrecy.
+	createdAt := time.Unix(int64(sessionState.createdAt), 0)
+	if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+		return nil
+	}
+
+	// Never resume a session for a different TLS version.
+	if c.vers != sessionState.version {
+		return nil
+	}
+
+	cipherSuiteOk := false
+	// Check that the client is still offering the ciphersuite in the session.
+	for _, id := range hs.clientHello.cipherSuites {
+		if id == sessionState.cipherSuite {
+			cipherSuiteOk = true
+			break
+		}
+	}
+	if !cipherSuiteOk {
+		return nil
+	}
+
+	// Check that we also support the ciphersuite from the session.
+	suite := selectCipherSuite([]uint16{sessionState.cipherSuite},
+		c.config.cipherSuites(), hs.cipherSuiteOk)
+	if suite == nil {
+		return nil
+	}
+
+	sessionHasClientCerts := len(sessionState.peerCertificates) != 0
+	needClientCerts := requiresClientCert(c.config.ClientAuth)
+	if needClientCerts && !sessionHasClientCerts {
+		return nil
+	}
+	if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
+		return nil
+	}
+	if sessionHasClientCerts && c.config.time().After(sessionState.peerCertificates[0].NotAfter) {
+		return nil
+	}
+	if sessionHasClientCerts && c.config.ClientAuth >= VerifyClientCertIfGiven &&
+		len(sessionState.verifiedChains) == 0 {
+		return nil
+	}
+
+	// RFC 7627, Section 5.3
+	if !sessionState.extMasterSecret && hs.clientHello.extendedMasterSecret {
+		return nil
+	}
+	if sessionState.extMasterSecret && !hs.clientHello.extendedMasterSecret {
+		// Aborting is somewhat harsh, but it's a MUST and it would indicate a
+		// weird downgrade in client capabilities.
+		return errors.New("tls: session supported extended_master_secret but client does not")
+	}
+
+	c.peerCertificates = sessionState.peerCertificates
+	c.ocspResponse = sessionState.ocspResponse
+	c.scts = sessionState.scts
+	c.verifiedChains = sessionState.verifiedChains
+	c.extMasterSecret = sessionState.extMasterSecret
+	hs.sessionState = sessionState
+	hs.suite = suite
+	c.didResume = true
+	return nil
+}
+
+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
+	// We always send a new session ticket, even if it wraps the same master
+	// secret and it's potentially encrypted with the same key, to help the
+	// client avoid cross-connection tracking from a network observer.
+	hs.hello.ticketSupported = true
+	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash.discardHandshakeBuffer()
+	if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
+		return err
+	}
+	if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
+		return err
+	}
+
+	if c.config.VerifyConnection != nil {
+		if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	hs.masterSecret = hs.sessionState.secret
+
+	return nil
+}
+
+func (hs *serverHandshakeState) doFullHandshake() error {
+	c := hs.c
+
+	if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
+		hs.hello.ocspStapling = true
+	}
+
+	hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
+	hs.hello.cipherSuite = hs.suite.id
+
+	hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
+	if c.config.ClientAuth == NoClientCert {
+		// No need to keep a full record of the handshake if client
+		// certificates won't be used.
+		hs.finishedHash.discardHandshakeBuffer()
+	}
+	if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
+		return err
+	}
+	if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
+		return err
+	}
+
+	certMsg := new(certificateMsg)
+	certMsg.certificates = hs.cert.Certificate
+	if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
+		return err
+	}
+
+	if hs.hello.ocspStapling {
+		certStatus := new(certificateStatusMsg)
+		certStatus.response = hs.cert.OCSPStaple
+		if _, err := hs.c.writeHandshakeRecord(certStatus, &hs.finishedHash); err != nil {
+			return err
+		}
+	}
+
+	keyAgreement := hs.suite.ka(c.vers)
+	skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	if skx != nil {
+		if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil {
+			return err
+		}
+	}
+
+	var certReq *certificateRequestMsg
+	if c.config.ClientAuth >= RequestClientCert {
+		// Request a client certificate
+		certReq = new(certificateRequestMsg)
+		certReq.certificateTypes = []byte{
+			byte(certTypeRSASign),
+			byte(certTypeECDSASign),
+		}
+		if c.vers >= VersionTLS12 {
+			certReq.hasSignatureAlgorithm = true
+			certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+		}
+
+		// An empty list of certificateAuthorities signals to
+		// the client that it may send any certificate in response
+		// to our request. When we know the CAs we trust, then
+		// we can send them down, so that the client can choose
+		// an appropriate certificate to give to us.
+		if c.config.ClientCAs != nil {
+			certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
+		}
+		if _, err := hs.c.writeHandshakeRecord(certReq, &hs.finishedHash); err != nil {
+			return err
+		}
+	}
+
+	helloDone := new(serverHelloDoneMsg)
+	if _, err := hs.c.writeHandshakeRecord(helloDone, &hs.finishedHash); err != nil {
+		return err
+	}
+
+	if _, err := c.flush(); err != nil {
+		return err
+	}
+
+	var pub crypto.PublicKey // public key for client auth, if any
+
+	msg, err := c.readHandshake(&hs.finishedHash)
+	if err != nil {
+		return err
+	}
+
+	// If we requested a client certificate, then the client must send a
+	// certificate message, even if it's empty.
+	if c.config.ClientAuth >= RequestClientCert {
+		certMsg, ok := msg.(*certificateMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certMsg, msg)
+		}
+
+		if err := c.processCertsFromClient(Certificate{
+			Certificate: certMsg.certificates,
+		}); err != nil {
+			return err
+		}
+		if len(certMsg.certificates) != 0 {
+			pub = c.peerCertificates[0].PublicKey
+		}
+
+		msg, err = c.readHandshake(&hs.finishedHash)
+		if err != nil {
+			return err
+		}
+	}
+	if c.config.VerifyConnection != nil {
+		if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	// Get client key exchange
+	ckx, ok := msg.(*clientKeyExchangeMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(ckx, msg)
+	}
+
+	preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	if hs.hello.extendedMasterSecret {
+		c.extMasterSecret = true
+		hs.masterSecret = extMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
+			hs.finishedHash.Sum())
+	} else {
+		hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
+			hs.clientHello.random, hs.hello.random)
+	}
+	if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+
+	// If we received a client cert in response to our certificate request message,
+	// the client will send us a certificateVerifyMsg immediately after the
+	// clientKeyExchangeMsg. This message is a digest of all preceding
+	// handshake-layer messages that is signed using the private key corresponding
+	// to the client's certificate. This allows us to verify that the client is in
+	// possession of the private key of the certificate.
+	if len(c.peerCertificates) > 0 {
+		// certificateVerifyMsg is included in the transcript, but not until
+		// after we verify the handshake signature, since the state before
+		// this message was sent is used.
+		msg, err = c.readHandshake(nil)
+		if err != nil {
+			return err
+		}
+		certVerify, ok := msg.(*certificateVerifyMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certVerify, msg)
+		}
+
+		var sigType uint8
+		var sigHash crypto.Hash
+		if c.vers >= VersionTLS12 {
+			if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, certReq.supportedSignatureAlgorithms) {
+				c.sendAlert(alertIllegalParameter)
+				return errors.New("tls: client certificate used with invalid signature algorithm")
+			}
+			sigType, sigHash, err = typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
+			if err != nil {
+				return c.sendAlert(alertInternalError)
+			}
+		} else {
+			sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub)
+			if err != nil {
+				c.sendAlert(alertIllegalParameter)
+				return err
+			}
+		}
+
+		signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash)
+		if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil {
+			c.sendAlert(alertDecryptError)
+			return errors.New("tls: invalid signature by the client certificate: " + err.Error())
+		}
+
+		if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil {
+			return err
+		}
+	}
+
+	hs.finishedHash.discardHandshakeBuffer()
+
+	return nil
+}
+
+func (hs *serverHandshakeState) establishKeys() error {
+	c := hs.c
+
+	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+
+	var clientCipher, serverCipher any
+	var clientHash, serverHash hash.Hash
+
+	if hs.suite.aead == nil {
+		clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
+		clientHash = hs.suite.mac(clientMAC)
+		serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
+		serverHash = hs.suite.mac(serverMAC)
+	} else {
+		clientCipher = hs.suite.aead(clientKey, clientIV)
+		serverCipher = hs.suite.aead(serverKey, serverIV)
+	}
+
+	c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
+	c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
+
+	return nil
+}
+
+func (hs *serverHandshakeState) readFinished(out []byte) error {
+	c := hs.c
+
+	if err := c.readChangeCipherSpec(); err != nil {
+		return err
+	}
+
+	// finishedMsg is included in the transcript, but not until after we
+	// check the client version, since the state before this message was
+	// sent is used during verification.
+	msg, err := c.readHandshake(nil)
+	if err != nil {
+		return err
+	}
+	clientFinished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(clientFinished, msg)
+	}
+
+	verify := hs.finishedHash.clientSum(hs.masterSecret)
+	if len(verify) != len(clientFinished.verifyData) ||
+		subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: client's Finished message is incorrect")
+	}
+
+	if err := transcriptMsg(clientFinished, &hs.finishedHash); err != nil {
+		return err
+	}
+
+	copy(out, verify)
+	return nil
+}
+
+func (hs *serverHandshakeState) sendSessionTicket() error {
+	if !hs.hello.ticketSupported {
+		return nil
+	}
+
+	c := hs.c
+	m := new(newSessionTicketMsg)
+
+	state, err := c.sessionState()
+	if err != nil {
+		return err
+	}
+	state.secret = hs.masterSecret
+	if hs.sessionState != nil {
+		// If this is re-wrapping an old key, then keep
+		// the original time it was created.
+		state.createdAt = hs.sessionState.createdAt
+	}
+	if c.config.WrapSession != nil {
+		m.ticket, err = c.config.WrapSession(c.connectionStateLocked(), toSessionState(state))
+		if err != nil {
+			return err
+		}
+	} else {
+		stateBytes, err := state.Bytes()
+		if err != nil {
+			return err
+		}
+		m.ticket, err = c.config.encryptTicket(stateBytes, c.ticketKeys)
+		if err != nil {
+			return err
+		}
+	}
+
+	if _, err := hs.c.writeHandshakeRecord(m, &hs.finishedHash); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeState) sendFinished(out []byte) error {
+	c := hs.c
+
+	if err := c.writeChangeCipherRecord(); err != nil {
+		return err
+	}
+
+	finished := new(finishedMsg)
+	finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+	if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
+		return err
+	}
+
+	copy(out, finished.verifyData)
+
+	return nil
+}
+
+// processCertsFromClient takes a chain of client certificates either from a
+// Certificates message and verifies them.
+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 certs[i].PublicKeyAlgorithm == x509.RSA {
+			n := certs[i].PublicKey.(*rsa.PublicKey).N.BitLen()
+			if max, ok := checkKeySize(n); !ok {
+				c.sendAlert(alertBadCertificate)
+				return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", max)
+			}
+		}
+	}
+
+	if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) {
+		if c.vers == VersionTLS13 {
+			c.sendAlert(alertCertificateRequired)
+		} else {
+			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 {
+			var errCertificateInvalid x509.CertificateInvalidError
+			if errors.As(err, &x509.UnknownAuthorityError{}) {
+				c.sendAlert(alertUnknownCA)
+			} else if errors.As(err, &errCertificateInvalid) && errCertificateInvalid.Reason == x509.Expired {
+				c.sendAlert(alertCertificateExpired)
+			} else {
+				c.sendAlert(alertBadCertificate)
+			}
+			return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+		}
+
+		c.verifiedChains = chains
+	}
+
+	c.peerCertificates = certs
+	c.ocspResponse = certificate.OCSPStaple
+	c.scts = certificate.SignedCertificateTimestamps
+
+	if len(certs) > 0 {
+		switch certs[0].PublicKey.(type) {
+		case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
+		default:
+			c.sendAlert(alertUnsupportedCertificate)
+			return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+		}
+	}
+
+	if c.config.VerifyPeerCertificate != nil {
+		if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	return nil
+}
+
+func newClientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
+	supportedVersions := clientHello.supportedVersions
+	if len(clientHello.supportedVersions) == 0 {
+		supportedVersions = supportedVersionsFromMax(clientHello.vers)
+	}
+
+	return toClientHelloInfo(&clientHelloInfo{
+		CipherSuites:      clientHello.cipherSuites,
+		ServerName:        clientHello.serverName,
+		SupportedCurves:   clientHello.supportedCurves,
+		SupportedPoints:   clientHello.supportedPoints,
+		SignatureSchemes:  clientHello.supportedSignatureAlgorithms,
+		SupportedProtos:   clientHello.alpnProtocols,
+		SupportedVersions: supportedVersions,
+		Conn:              c.conn,
+		config:            toConfig(c.config),
+		ctx:               ctx,
+	})
+}

+ 991 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/handshake_server_tls13.go

@@ -0,0 +1,991 @@
+// 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"
+	"hash"
+	"io"
+	"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
+	earlyData       bool
+	suite           *cipherSuiteTLS13
+	cert            *Certificate
+	sigAlg          SignatureScheme
+	earlySecret     []byte
+	sharedKey       []byte
+	handshakeSecret []byte
+	masterSecret    []byte
+	trafficSecret   []byte // client_application_traffic_secret_0
+	transcript      hash.Hash
+	clientFinished  []byte
+}
+
+func (hs *serverHandshakeStateTLS13) handshake() error {
+	c := hs.c
+
+	// 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.isHandshakeComplete.Store(true)
+
+	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 && c.quic != nil {
+		if len(hs.clientHello.pskIdentities) == 0 {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: early_data without pre_shared_key")
+		}
+	} else 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
+	}
+	if needFIPS() {
+		preferenceList = defaultCipherSuitesTLS13FIPS
+	}
+	for _, suiteID := range preferenceList {
+		hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID)
+		if hs.suite != nil {
+			break
+		}
+	}
+	if hs.suite == nil {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: no cipher suite supported by both client and server")
+	}
+	c.cipherSuite = hs.suite.id
+	hs.hello.cipherSuite = hs.suite.id
+	hs.transcript = hs.suite.hash.New()
+
+	// Pick the ECDHE group in server preference order, but give priority to
+	// groups with a key share, to avoid a HelloRetryRequest round-trip.
+	var selectedGroup CurveID
+	var clientKeyShare *keyShare
+GroupSelection:
+	for _, preferredGroup := range c.config.curvePreferences() {
+		for _, ks := range hs.clientHello.keyShares {
+			if ks.group == preferredGroup {
+				selectedGroup = ks.group
+				clientKeyShare = &ks
+				break GroupSelection
+			}
+		}
+		if selectedGroup != 0 {
+			continue
+		}
+		for _, group := range hs.clientHello.supportedCurves {
+			if group == preferredGroup {
+				selectedGroup = group
+				break
+			}
+		}
+	}
+	if selectedGroup == 0 {
+		c.sendAlert(alertHandshakeFailure)
+		return errors.New("tls: no ECDHE curve supported by both client and server")
+	}
+	if clientKeyShare == nil {
+		if err := hs.doHelloRetryRequest(selectedGroup); err != nil {
+			return err
+		}
+		clientKeyShare = &hs.clientHello.keyShares[0]
+	}
+
+	if _, ok := curveForCurveID(selectedGroup); !ok {
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: CurvePreferences includes unsupported curve")
+	}
+	key, err := generateECDHEKey(c.config.rand(), selectedGroup)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+	hs.hello.serverShare = keyShare{group: selectedGroup, data: key.PublicKey().Bytes()}
+	peerKey, err := key.Curve().NewPublicKey(clientKeyShare.data)
+	if err != nil {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: invalid client key share")
+	}
+	hs.sharedKey, err = key.ECDH(peerKey)
+	if err != nil {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: invalid client key share")
+	}
+
+	selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil)
+	if err != nil {
+		c.sendAlert(alertNoApplicationProtocol)
+		return err
+	}
+	c.clientProtocol = selectedProto
+
+	if c.quic != nil {
+		if hs.clientHello.quicTransportParameters == nil {
+			// RFC 9001 Section 8.2.
+			c.sendAlert(alertMissingExtension)
+			return errors.New("tls: client did not send a quic_transport_parameters extension")
+		}
+		c.quicSetTransportParameters(hs.clientHello.quicTransportParameters)
+	} else {
+		if hs.clientHello.quicTransportParameters != nil {
+			c.sendAlert(alertUnsupportedExtension)
+			return errors.New("tls: client sent an unexpected quic_transport_parameters extension")
+		}
+	}
+
+	c.serverName = hs.clientHello.serverName
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) checkForResumption() error {
+	c := hs.c
+
+	if c.config.SessionTicketsDisabled {
+		return nil
+	}
+
+	modeOK := false
+	for _, mode := range hs.clientHello.pskModes {
+		if mode == pskModeDHE {
+			modeOK = true
+			break
+		}
+	}
+	if !modeOK {
+		return nil
+	}
+
+	if len(hs.clientHello.pskIdentities) != len(hs.clientHello.pskBinders) {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: invalid or missing PSK binders")
+	}
+	if len(hs.clientHello.pskIdentities) == 0 {
+		return nil
+	}
+
+	for i, identity := range hs.clientHello.pskIdentities {
+		if i >= maxClientPSKIdentities {
+			break
+		}
+
+		var sessionState *sessionState
+		if c.config.UnwrapSession != nil {
+			var err error
+			ss, err := c.config.UnwrapSession(identity.label, c.connectionStateLocked())
+			if err != nil {
+				return err
+			}
+			if ss == nil {
+				continue
+			}
+			sessionState = fromSessionState(ss)
+		} else {
+			plaintext := c.config.decryptTicket(identity.label, c.ticketKeys)
+			if plaintext == nil {
+				continue
+			}
+			var err error
+			sessionState, err = ParseSessionState(plaintext)
+			if err != nil {
+				continue
+			}
+		}
+
+		if sessionState.version != VersionTLS13 {
+			continue
+		}
+
+		createdAt := time.Unix(int64(sessionState.createdAt), 0)
+		if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+			continue
+		}
+
+		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.peerCertificates) != 0
+		needClientCerts := requiresClientCert(c.config.ClientAuth)
+		if needClientCerts && !sessionHasClientCerts {
+			continue
+		}
+		if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
+			continue
+		}
+		if sessionHasClientCerts && c.config.time().After(sessionState.peerCertificates[0].NotAfter) {
+			continue
+		}
+		if sessionHasClientCerts && c.config.ClientAuth >= VerifyClientCertIfGiven &&
+			len(sessionState.verifiedChains) == 0 {
+			continue
+		}
+
+		hs.earlySecret = hs.suite.extract(sessionState.secret, nil)
+		binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil)
+		// Clone the transcript in case a HelloRetryRequest was recorded.
+		transcript := cloneHash(hs.transcript, hs.suite.hash)
+		if transcript == nil {
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: internal error: failed to clone hash")
+		}
+		clientHelloBytes, err := hs.clientHello.marshalWithoutBinders()
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		transcript.Write(clientHelloBytes)
+		pskBinder := hs.suite.finishedHash(binderKey, transcript)
+		if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) {
+			c.sendAlert(alertDecryptError)
+			return errors.New("tls: invalid PSK binder")
+		}
+
+		if c.quic != nil && hs.clientHello.earlyData && i == 0 &&
+			sessionState.EarlyData && sessionState.cipherSuite == hs.suite.id &&
+			sessionState.alpnProtocol == c.clientProtocol {
+			hs.earlyData = true
+
+			transcript := hs.suite.hash.New()
+			if err := transcriptMsg(hs.clientHello, transcript); err != nil {
+				return err
+			}
+			earlyTrafficSecret := hs.suite.deriveSecret(hs.earlySecret, clientEarlyTrafficLabel, transcript)
+			c.quicSetReadSecret(QUICEncryptionLevelEarly, hs.suite.id, earlyTrafficSecret)
+		}
+
+		c.didResume = true
+		c.peerCertificates = sessionState.peerCertificates
+		c.ocspResponse = sessionState.ocspResponse
+		c.scts = sessionState.scts
+		c.verifiedChains = sessionState.verifiedChains
+
+		hs.hello.selectedIdentityPresent = true
+		hs.hello.selectedIdentity = uint16(i)
+		hs.usingPSK = true
+		return nil
+	}
+
+	return nil
+}
+
+// cloneHash uses the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler
+// interfaces implemented by standard library hashes to clone the state of in
+// to a new instance of h. It returns nil if the operation fails.
+func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash {
+	// Recreate the interface to avoid importing encoding.
+	type binaryMarshaler interface {
+		MarshalBinary() (data []byte, err error)
+		UnmarshalBinary(data []byte) error
+	}
+	marshaler, ok := in.(binaryMarshaler)
+	if !ok {
+		return nil
+	}
+	state, err := marshaler.MarshalBinary()
+	if err != nil {
+		return nil
+	}
+	out := h.New()
+	unmarshaler, ok := out.(binaryMarshaler)
+	if !ok {
+		return nil
+	}
+	if err := unmarshaler.UnmarshalBinary(state); err != nil {
+		return nil
+	}
+	return out
+}
+
+func (hs *serverHandshakeStateTLS13) pickCertificate() error {
+	c := hs.c
+
+	// Only one of PSK and certificates are used at a time.
+	if hs.usingPSK {
+		return nil
+	}
+
+	// signature_algorithms is required in TLS 1.3. See RFC 8446, Section 4.2.3.
+	if len(hs.clientHello.supportedSignatureAlgorithms) == 0 {
+		return c.sendAlert(alertMissingExtension)
+	}
+
+	certificate, err := c.config.getCertificate(newClientHelloInfo(hs.ctx, c, hs.clientHello))
+	if err != nil {
+		if err == errNoCertificates {
+			c.sendAlert(alertUnrecognizedName)
+		} else {
+			c.sendAlert(alertInternalError)
+		}
+		return err
+	}
+	hs.sigAlg, err = selectSignatureScheme(c.vers, certificate, hs.clientHello.supportedSignatureAlgorithms)
+	if err != nil {
+		// getCertificate returned a certificate that is unsupported or
+		// incompatible with the client's signature algorithms.
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	hs.cert = certificate
+
+	return nil
+}
+
+// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
+// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
+func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
+	if hs.c.quic != nil {
+		return nil
+	}
+	if hs.sentDummyCCS {
+		return nil
+	}
+	hs.sentDummyCCS = true
+
+	return hs.c.writeChangeCipherRecord()
+}
+
+func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error {
+	c := hs.c
+
+	// The first ClientHello gets double-hashed into the transcript upon a
+	// HelloRetryRequest. See RFC 8446, Section 4.4.1.
+	if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
+		return err
+	}
+	chHash := hs.transcript.Sum(nil)
+	hs.transcript.Reset()
+	hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+	hs.transcript.Write(chHash)
+
+	helloRetryRequest := &serverHelloMsg{
+		vers:              hs.hello.vers,
+		random:            helloRetryRequestRandom,
+		sessionId:         hs.hello.sessionId,
+		cipherSuite:       hs.hello.cipherSuite,
+		compressionMethod: hs.hello.compressionMethod,
+		supportedVersion:  hs.hello.supportedVersion,
+		selectedGroup:     selectedGroup,
+	}
+
+	if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil {
+		return err
+	}
+
+	if err := hs.sendDummyChangeCipherSpec(); err != nil {
+		return err
+	}
+
+	// clientHelloMsg is not included in the transcript.
+	msg, err := c.readHandshake(nil)
+	if err != nil {
+		return err
+	}
+
+	clientHello, ok := msg.(*clientHelloMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(clientHello, msg)
+	}
+
+	if len(clientHello.keyShares) != 1 || clientHello.keyShares[0].group != selectedGroup {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: client sent invalid key share in second ClientHello")
+	}
+
+	if clientHello.earlyData {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: client indicated early data in second ClientHello")
+	}
+
+	if illegalClientHelloChange(clientHello, hs.clientHello) {
+		c.sendAlert(alertIllegalParameter)
+		return errors.New("tls: client illegally modified second ClientHello")
+	}
+
+	hs.clientHello = clientHello
+	return nil
+}
+
+// illegalClientHelloChange reports whether the two ClientHello messages are
+// different, with the exception of the changes allowed before and after a
+// HelloRetryRequest. See RFC 8446, Section 4.1.2.
+func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool {
+	if len(ch.supportedVersions) != len(ch1.supportedVersions) ||
+		len(ch.cipherSuites) != len(ch1.cipherSuites) ||
+		len(ch.supportedCurves) != len(ch1.supportedCurves) ||
+		len(ch.supportedSignatureAlgorithms) != len(ch1.supportedSignatureAlgorithms) ||
+		len(ch.supportedSignatureAlgorithmsCert) != len(ch1.supportedSignatureAlgorithmsCert) ||
+		len(ch.alpnProtocols) != len(ch1.alpnProtocols) {
+		return true
+	}
+	for i := range ch.supportedVersions {
+		if ch.supportedVersions[i] != ch1.supportedVersions[i] {
+			return true
+		}
+	}
+	for i := range ch.cipherSuites {
+		if ch.cipherSuites[i] != ch1.cipherSuites[i] {
+			return true
+		}
+	}
+	for i := range ch.supportedCurves {
+		if ch.supportedCurves[i] != ch1.supportedCurves[i] {
+			return true
+		}
+	}
+	for i := range ch.supportedSignatureAlgorithms {
+		if ch.supportedSignatureAlgorithms[i] != ch1.supportedSignatureAlgorithms[i] {
+			return true
+		}
+	}
+	for i := range ch.supportedSignatureAlgorithmsCert {
+		if ch.supportedSignatureAlgorithmsCert[i] != ch1.supportedSignatureAlgorithmsCert[i] {
+			return true
+		}
+	}
+	for i := range ch.alpnProtocols {
+		if ch.alpnProtocols[i] != ch1.alpnProtocols[i] {
+			return true
+		}
+	}
+	return ch.vers != ch1.vers ||
+		!bytes.Equal(ch.random, ch1.random) ||
+		!bytes.Equal(ch.sessionId, ch1.sessionId) ||
+		!bytes.Equal(ch.compressionMethods, ch1.compressionMethods) ||
+		ch.serverName != ch1.serverName ||
+		ch.ocspStapling != ch1.ocspStapling ||
+		!bytes.Equal(ch.supportedPoints, ch1.supportedPoints) ||
+		ch.ticketSupported != ch1.ticketSupported ||
+		!bytes.Equal(ch.sessionTicket, ch1.sessionTicket) ||
+		ch.secureRenegotiationSupported != ch1.secureRenegotiationSupported ||
+		!bytes.Equal(ch.secureRenegotiation, ch1.secureRenegotiation) ||
+		ch.scts != ch1.scts ||
+		!bytes.Equal(ch.cookie, ch1.cookie) ||
+		!bytes.Equal(ch.pskModes, ch1.pskModes)
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
+	c := hs.c
+
+	if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
+		return err
+	}
+	if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
+		return err
+	}
+
+	if err := hs.sendDummyChangeCipherSpec(); err != nil {
+		return err
+	}
+
+	earlySecret := hs.earlySecret
+	if earlySecret == nil {
+		earlySecret = hs.suite.extract(nil, nil)
+	}
+	hs.handshakeSecret = hs.suite.extract(hs.sharedKey,
+		hs.suite.deriveSecret(earlySecret, "derived", nil))
+
+	clientSecret := hs.suite.deriveSecret(hs.handshakeSecret,
+		clientHandshakeTrafficLabel, hs.transcript)
+	c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret)
+	serverSecret := hs.suite.deriveSecret(hs.handshakeSecret,
+		serverHandshakeTrafficLabel, hs.transcript)
+	c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret)
+
+	if c.quic != nil {
+		if c.hand.Len() != 0 {
+			c.sendAlert(alertUnexpectedMessage)
+		}
+		c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret)
+		c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret)
+	}
+
+	err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret)
+	if err != nil {
+		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)
+	encryptedExtensions.alpnProtocol = c.clientProtocol
+
+	if c.quic != nil {
+		p, err := c.quicGetTransportParameters()
+		if err != nil {
+			return err
+		}
+		encryptedExtensions.quicTransportParameters = p
+		encryptedExtensions.earlyData = hs.earlyData
+	}
+
+	if _, err := hs.c.writeHandshakeRecord(encryptedExtensions, hs.transcript); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) requestClientCert() bool {
+	return hs.c.config.ClientAuth >= RequestClientCert && !hs.usingPSK
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
+	c := hs.c
+
+	// Only one of PSK and certificates are used at a time.
+	if hs.usingPSK {
+		return nil
+	}
+
+	if hs.requestClientCert() {
+		// Request a client certificate
+		certReq := new(certificateRequestMsgTLS13)
+		certReq.ocspStapling = true
+		certReq.scts = true
+		certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+		if c.config.ClientCAs != nil {
+			certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
+		}
+
+		if _, err := hs.c.writeHandshakeRecord(certReq, hs.transcript); err != nil {
+			return err
+		}
+	}
+
+	certMsg := new(certificateMsgTLS13)
+
+	certMsg.certificate = *hs.cert
+	certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0
+	certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0
+
+	if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
+		return err
+	}
+
+	certVerifyMsg := new(certificateVerifyMsg)
+	certVerifyMsg.hasSignatureAlgorithm = true
+	certVerifyMsg.signatureAlgorithm = hs.sigAlg
+
+	sigType, sigHash, err := typeAndHashFromSignatureScheme(hs.sigAlg)
+	if err != nil {
+		return c.sendAlert(alertInternalError)
+	}
+
+	signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
+	signOpts := crypto.SignerOpts(sigHash)
+	if sigType == signatureRSAPSS {
+		signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+	}
+	sig, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts)
+	if err != nil {
+		public := hs.cert.PrivateKey.(crypto.Signer).Public()
+		if rsaKey, ok := public.(*rsa.PublicKey); ok && sigType == signatureRSAPSS &&
+			rsaKey.N.BitLen()/8 < sigHash.Size()*2+2 { // key too small for RSA-PSS
+			c.sendAlert(alertHandshakeFailure)
+		} else {
+			c.sendAlert(alertInternalError)
+		}
+		return errors.New("tls: failed to sign handshake: " + err.Error())
+	}
+	certVerifyMsg.signature = sig
+
+	if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
+	c := hs.c
+
+	finished := &finishedMsg{
+		verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
+	}
+
+	if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
+		return err
+	}
+
+	// Derive secrets that take context through the server Finished.
+
+	hs.masterSecret = hs.suite.extract(nil,
+		hs.suite.deriveSecret(hs.handshakeSecret, "derived", nil))
+
+	hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
+		clientApplicationTrafficLabel, hs.transcript)
+	serverSecret := hs.suite.deriveSecret(hs.masterSecret,
+		serverApplicationTrafficLabel, hs.transcript)
+	c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret)
+
+	if c.quic != nil {
+		if c.hand.Len() != 0 {
+			// TODO: Handle this in setTrafficSecret?
+			c.sendAlert(alertUnexpectedMessage)
+		}
+		c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, serverSecret)
+	}
+
+	err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+	err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.clientHello.random, serverSecret)
+	if err != nil {
+		c.sendAlert(alertInternalError)
+		return err
+	}
+
+	c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
+
+	// If we did not request client certificates, at this point we can
+	// precompute the client finished and roll the transcript forward to send
+	// session tickets in our first flight.
+	if !hs.requestClientCert() {
+		if err := hs.sendSessionTickets(); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool {
+	if hs.c.config.SessionTicketsDisabled {
+		return false
+	}
+
+	// QUIC tickets are sent by QUICConn.SendSessionTicket, not automatically.
+	if hs.c.quic != nil {
+		return false
+	}
+
+	// Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9.
+	for _, pskMode := range hs.clientHello.pskModes {
+		if pskMode == pskModeDHE {
+			return true
+		}
+	}
+	return false
+}
+
+func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
+	c := hs.c
+
+	hs.clientFinished = hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
+	finishedMsg := &finishedMsg{
+		verifyData: hs.clientFinished,
+	}
+	if err := transcriptMsg(finishedMsg, hs.transcript); err != nil {
+		return err
+	}
+
+	c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
+		resumptionLabel, hs.transcript)
+
+	if !hs.shouldSendSessionTickets() {
+		return nil
+	}
+	return c.sendSessionTicket(false)
+}
+
+func (c *Conn) sendSessionTicket(earlyData bool) error {
+	suite := cipherSuiteTLS13ByID(c.cipherSuite)
+	if suite == nil {
+		return errors.New("tls: internal error: unknown cipher suite")
+	}
+	// ticket_nonce, which must be unique per connection, is always left at
+	// zero because we only ever send one ticket per connection.
+	psk := suite.expandLabel(c.resumptionSecret, "resumption",
+		nil, suite.hash.Size())
+
+	m := new(newSessionTicketMsgTLS13)
+
+	state, err := c.sessionState()
+	if err != nil {
+		return err
+	}
+	state.secret = psk
+	state.EarlyData = earlyData
+	if c.config.WrapSession != nil {
+		m.label, err = c.config.WrapSession(c.connectionStateLocked(), toSessionState(state))
+		if err != nil {
+			return err
+		}
+	} else {
+		stateBytes, err := state.Bytes()
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		m.label, err = c.config.encryptTicket(stateBytes, c.ticketKeys)
+		if err != nil {
+			return err
+		}
+	}
+	m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
+
+	// ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1
+	// The value is not stored anywhere; we never need to check the ticket age
+	// because 0-RTT is not supported.
+	ageAdd := make([]byte, 4)
+	_, err = c.config.rand().Read(ageAdd)
+	if err != nil {
+		return err
+	}
+	m.ageAdd = binary.LittleEndian.Uint32(ageAdd)
+
+	if earlyData {
+		// RFC 9001, Section 4.6.1
+		m.maxEarlyData = 0xffffffff
+	}
+
+	if _, err := c.writeHandshakeRecord(m, nil); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
+	c := hs.c
+
+	if !hs.requestClientCert() {
+		// Make sure the connection is still being verified whether or not
+		// the server requested a client certificate.
+		if c.config.VerifyConnection != nil {
+			if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+				c.sendAlert(alertBadCertificate)
+				return err
+			}
+		}
+		return nil
+	}
+
+	// If we requested a client certificate, then the client must send a
+	// certificate message. If it's empty, no CertificateVerify is sent.
+
+	msg, err := c.readHandshake(hs.transcript)
+	if err != nil {
+		return err
+	}
+
+	certMsg, ok := msg.(*certificateMsgTLS13)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(certMsg, msg)
+	}
+
+	if err := c.processCertsFromClient(certMsg.certificate); err != nil {
+		return err
+	}
+
+	if c.config.VerifyConnection != nil {
+		if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
+	if len(certMsg.certificate.Certificate) != 0 {
+		// certificateVerifyMsg is included in the transcript, but not until
+		// after we verify the handshake signature, since the state before
+		// this message was sent is used.
+		msg, err = c.readHandshake(nil)
+		if err != nil {
+			return err
+		}
+
+		certVerify, ok := msg.(*certificateVerifyMsg)
+		if !ok {
+			c.sendAlert(alertUnexpectedMessage)
+			return unexpectedMessageError(certVerify, msg)
+		}
+
+		// See RFC 8446, Section 4.4.3.
+		if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: client certificate used with invalid signature algorithm")
+		}
+		sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
+		if err != nil {
+			return c.sendAlert(alertInternalError)
+		}
+		if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: client certificate used with invalid signature algorithm")
+		}
+		signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
+		if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
+			sigHash, signed, certVerify.signature); err != nil {
+			c.sendAlert(alertDecryptError)
+			return errors.New("tls: invalid signature by the client certificate: " + err.Error())
+		}
+
+		if err := transcriptMsg(certVerify, hs.transcript); err != nil {
+			return err
+		}
+	}
+
+	// If we waited until the client certificates to send session tickets, we
+	// are ready to do it now.
+	if err := hs.sendSessionTickets(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (hs *serverHandshakeStateTLS13) readClientFinished() error {
+	c := hs.c
+
+	// finishedMsg is not included in the transcript.
+	msg, err := c.readHandshake(nil)
+	if err != nil {
+		return err
+	}
+
+	finished, ok := msg.(*finishedMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return unexpectedMessageError(finished, msg)
+	}
+
+	if !hmac.Equal(hs.clientFinished, finished.verifyData) {
+		c.sendAlert(alertDecryptError)
+		return errors.New("tls: invalid client finished hash")
+	}
+
+	c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret)
+
+	return nil
+}

+ 366 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/key_agreement.go

@@ -0,0 +1,366 @@
+// 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/ecdh"
+	"crypto/md5"
+	"crypto/rsa"
+	"crypto/sha1"
+	"crypto/x509"
+	"errors"
+	"fmt"
+	"io"
+)
+
+// a keyAgreement implements the client and server side of a TLS key agreement
+// protocol by generating and processing key exchange messages.
+type keyAgreement interface {
+	// On the server side, the first two methods are called in order.
+
+	// In the case that the key agreement protocol doesn't use a
+	// ServerKeyExchange message, generateServerKeyExchange can return nil,
+	// nil.
+	generateServerKeyExchange(*config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
+	processClientKeyExchange(*config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
+
+	// On the client side, the next two methods are called in order.
+
+	// This method may not be called if the server doesn't send a
+	// ServerKeyExchange message.
+	processServerKeyExchange(*config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
+	generateClientKeyExchange(*config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
+}
+
+var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
+var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
+
+// rsaKeyAgreement implements the standard TLS key agreement where the client
+// encrypts the pre-master secret to the server's public key.
+type rsaKeyAgreement struct{}
+
+func (ka rsaKeyAgreement) generateServerKeyExchange(config *config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	return nil, nil
+}
+
+func (ka rsaKeyAgreement) processClientKeyExchange(config *config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	if len(ckx.ciphertext) < 2 {
+		return nil, errClientKeyExchange
+	}
+	ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+	if ciphertextLen != len(ckx.ciphertext)-2 {
+		return nil, errClientKeyExchange
+	}
+	ciphertext := ckx.ciphertext[2:]
+
+	priv, ok := cert.PrivateKey.(crypto.Decrypter)
+	if !ok {
+		return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
+	}
+	// Perform constant time RSA PKCS #1 v1.5 decryption
+	preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
+	if err != nil {
+		return nil, err
+	}
+	// We don't check the version number in the premaster secret. For one,
+	// by checking it, we would leak information about the validity of the
+	// encrypted pre-master secret. Secondly, it provides only a small
+	// benefit against a downgrade attack and some implementations send the
+	// wrong version anyway. See the discussion at the end of section
+	// 7.4.7.1 of RFC 4346.
+	return preMasterSecret, nil
+}
+
+func (ka rsaKeyAgreement) processServerKeyExchange(config *config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+	return errors.New("tls: unexpected ServerKeyExchange")
+}
+
+func (ka rsaKeyAgreement) generateClientKeyExchange(config *config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+	preMasterSecret := make([]byte, 48)
+	preMasterSecret[0] = byte(clientHello.vers >> 8)
+	preMasterSecret[1] = byte(clientHello.vers)
+	_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+	if err != nil {
+		return nil, nil, err
+	}
+
+	rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
+	if !ok {
+		return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
+	}
+	encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret)
+	if err != nil {
+		return nil, nil, err
+	}
+	ckx := new(clientKeyExchangeMsg)
+	ckx.ciphertext = make([]byte, len(encrypted)+2)
+	ckx.ciphertext[0] = byte(len(encrypted) >> 8)
+	ckx.ciphertext[1] = byte(len(encrypted))
+	copy(ckx.ciphertext[2:], encrypted)
+	return preMasterSecret, ckx, nil
+}
+
+// sha1Hash calculates a SHA1 hash over the given byte slices.
+func sha1Hash(slices [][]byte) []byte {
+	hsha1 := sha1.New()
+	for _, slice := range slices {
+		hsha1.Write(slice)
+	}
+	return hsha1.Sum(nil)
+}
+
+// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
+// concatenation of an MD5 and SHA1 hash.
+func md5SHA1Hash(slices [][]byte) []byte {
+	md5sha1 := make([]byte, md5.Size+sha1.Size)
+	hmd5 := md5.New()
+	for _, slice := range slices {
+		hmd5.Write(slice)
+	}
+	copy(md5sha1, hmd5.Sum(nil))
+	copy(md5sha1[md5.Size:], sha1Hash(slices))
+	return md5sha1
+}
+
+// hashForServerKeyExchange hashes the given slices and returns their digest
+// using the given hash function (for >= TLS 1.2) or using a default based on
+// the sigType (for earlier TLS versions). For Ed25519 signatures, which don't
+// do pre-hashing, it returns the concatenation of the slices.
+func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte {
+	if sigType == signatureEd25519 {
+		var signed []byte
+		for _, slice := range slices {
+			signed = append(signed, slice...)
+		}
+		return signed
+	}
+	if version >= VersionTLS12 {
+		h := hashFunc.New()
+		for _, slice := range slices {
+			h.Write(slice)
+		}
+		digest := h.Sum(nil)
+		return digest
+	}
+	if sigType == signatureECDSA {
+		return sha1Hash(slices)
+	}
+	return md5SHA1Hash(slices)
+}
+
+// ecdheKeyAgreement implements a TLS key agreement where the server
+// generates an ephemeral EC public/private key pair and signs it. The
+// pre-master secret is then calculated using ECDH. The signature may
+// be ECDSA, Ed25519 or RSA.
+type ecdheKeyAgreement struct {
+	version uint16
+	isRSA   bool
+	key     *ecdh.PrivateKey
+
+	// ckx and preMasterSecret are generated in processServerKeyExchange
+	// and returned in generateClientKeyExchange.
+	ckx             *clientKeyExchangeMsg
+	preMasterSecret []byte
+}
+
+func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+	var curveID CurveID
+	for _, c := range clientHello.supportedCurves {
+		if config.supportsCurve(c) {
+			curveID = c
+			break
+		}
+	}
+
+	if curveID == 0 {
+		return nil, errors.New("tls: no supported elliptic curves offered")
+	}
+	if _, ok := curveForCurveID(curveID); !ok {
+		return nil, errors.New("tls: CurvePreferences includes unsupported curve")
+	}
+
+	key, err := generateECDHEKey(config.rand(), curveID)
+	if err != nil {
+		return nil, err
+	}
+	ka.key = key
+
+	// See RFC 4492, Section 5.4.
+	ecdhePublic := key.PublicKey().Bytes()
+	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
+	}
+
+	peerKey, err := ka.key.Curve().NewPublicKey(ckx.ciphertext[1:])
+	if err != nil {
+		return nil, errClientKeyExchange
+	}
+	preMasterSecret, err := ka.key.ECDH(peerKey)
+	if err != 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); !ok {
+		return errors.New("tls: server selected unsupported curve")
+	}
+
+	key, err := generateECDHEKey(config.rand(), curveID)
+	if err != nil {
+		return err
+	}
+	ka.key = key
+
+	peerKey, err := key.Curve().NewPublicKey(publicKey)
+	if err != nil {
+		return errServerKeyExchange
+	}
+	ka.preMasterSecret, err = key.ECDH(peerKey)
+	if err != nil {
+		return errServerKeyExchange
+	}
+
+	ourPublicKey := key.PublicKey().Bytes()
+	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
+}

+ 159 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/key_schedule.go

@@ -0,0 +1,159 @@
+// 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/ecdh"
+	"crypto/hmac"
+	"errors"
+	"fmt"
+	"hash"
+	"io"
+
+	"golang.org/x/crypto/cryptobyte"
+	"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"
+	clientEarlyTrafficLabel       = "c e traffic"
+	clientHandshakeTrafficLabel   = "c hs traffic"
+	serverHandshakeTrafficLabel   = "s hs traffic"
+	clientApplicationTrafficLabel = "c ap traffic"
+	serverApplicationTrafficLabel = "s ap traffic"
+	exporterLabel                 = "exp master"
+	resumptionLabel               = "res master"
+	trafficUpdateLabel            = "traffic upd"
+)
+
+// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
+func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte {
+	var hkdfLabel cryptobyte.Builder
+	hkdfLabel.AddUint16(uint16(length))
+	hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes([]byte("tls13 "))
+		b.AddBytes([]byte(label))
+	})
+	hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(context)
+	})
+	hkdfLabelBytes, err := hkdfLabel.Bytes()
+	if err != nil {
+		// Rather than calling BytesOrPanic, we explicitly handle this error, in
+		// order to provide a reasonable error message. It should be basically
+		// impossible for this to panic, and routing errors back through the
+		// tree rooted in this function is quite painful. The labels are fixed
+		// size, and the context is either a fixed-length computed hash, or
+		// parsed from a field which has the same length limitation. As such, an
+		// error here is likely to only be caused during development.
+		//
+		// NOTE: another reasonable approach here might be to return a
+		// randomized slice if we encounter an error, which would break the
+		// connection, but avoid panicking. This would perhaps be safer but
+		// significantly more confusing to users.
+		panic(fmt.Errorf("failed to construct HKDF label: %s", err))
+	}
+	out := make([]byte, length)
+	n, err := hkdf.Expand(c.hash.New, secret, hkdfLabelBytes).Read(out)
+	if err != nil || n != length {
+		panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
+	}
+	return out
+}
+
+// deriveSecret implements Derive-Secret from RFC 8446, Section 7.1.
+func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte {
+	if transcript == nil {
+		transcript = c.hash.New()
+	}
+	return c.expandLabel(secret, label, transcript.Sum(nil), c.hash.Size())
+}
+
+// extract implements HKDF-Extract with the cipher suite hash.
+func (c *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte {
+	if newSecret == nil {
+		newSecret = make([]byte, c.hash.Size())
+	}
+	return hkdf.Extract(c.hash.New, newSecret, currentSecret)
+}
+
+// nextTrafficSecret generates the next traffic secret, given the current one,
+// according to RFC 8446, Section 7.2.
+func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte {
+	return c.expandLabel(trafficSecret, trafficUpdateLabel, nil, c.hash.Size())
+}
+
+// trafficKey generates traffic keys according to RFC 8446, Section 7.3.
+func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) {
+	key = c.expandLabel(trafficSecret, "key", nil, c.keyLen)
+	iv = c.expandLabel(trafficSecret, "iv", nil, aeadNonceLength)
+	return
+}
+
+// finishedHash generates the Finished verify_data or PskBinderEntry according
+// to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey
+// selection.
+func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte {
+	finishedKey := c.expandLabel(baseKey, "finished", nil, c.hash.Size())
+	verifyData := hmac.New(c.hash.New, finishedKey)
+	verifyData.Write(transcript.Sum(nil))
+	return verifyData.Sum(nil)
+}
+
+// exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to
+// RFC 8446, Section 7.5.
+func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) {
+	expMasterSecret := c.deriveSecret(masterSecret, exporterLabel, transcript)
+	return func(label string, context []byte, length int) ([]byte, error) {
+		secret := c.deriveSecret(expMasterSecret, label, nil)
+		h := c.hash.New()
+		h.Write(context)
+		return c.expandLabel(secret, "exporter", h.Sum(nil), length), nil
+	}
+}
+
+// generateECDHEKey returns a PrivateKey that implements Diffie-Hellman
+// according to RFC 8446, Section 4.2.8.2.
+func generateECDHEKey(rand io.Reader, curveID CurveID) (*ecdh.PrivateKey, error) {
+	curve, ok := curveForCurveID(curveID)
+	if !ok {
+		return nil, errors.New("tls: internal error: unsupported curve")
+	}
+
+	return curve.GenerateKey(rand)
+}
+
+func curveForCurveID(id CurveID) (ecdh.Curve, bool) {
+	switch id {
+	case X25519:
+		return ecdh.X25519(), true
+	case CurveP256:
+		return ecdh.P256(), true
+	case CurveP384:
+		return ecdh.P384(), true
+	case CurveP521:
+		return ecdh.P521(), true
+	default:
+		return nil, false
+	}
+}
+
+func curveIDForCurve(curve ecdh.Curve) (CurveID, bool) {
+	switch curve {
+	case ecdh.X25519():
+		return X25519, true
+	case ecdh.P256():
+		return CurveP256, true
+	case ecdh.P384():
+		return CurveP384, true
+	case ecdh.P521():
+		return CurveP521, true
+	default:
+		return 0, false
+	}
+}

+ 22 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/notboring.go

@@ -0,0 +1,22 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !boringcrypto
+
+package tls
+
+func needFIPS() bool { return false }
+
+func supportedSignatureAlgorithms() []SignatureScheme {
+	return defaultSupportedSignatureAlgorithms
+}
+
+func fipsMinVersion(c *config) uint16          { panic("fipsMinVersion") }
+func fipsMaxVersion(c *config) uint16          { panic("fipsMaxVersion") }
+func fipsCurvePreferences(c *config) []CurveID { panic("fipsCurvePreferences") }
+func fipsCipherSuites(c *config) []uint16      { panic("fipsCipherSuites") }
+
+var fipsSupportedSignatureAlgorithms []SignatureScheme
+
+var defaultCipherSuitesTLS13FIPS []uint16

+ 292 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/prf.go

@@ -0,0 +1,292 @@
+// 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")
+var extendedMasterSecretLabel = []byte("extended master secret")
+var keyExpansionLabel = []byte("key expansion")
+var clientFinishedLabel = []byte("client finished")
+var serverFinishedLabel = []byte("server finished")
+
+func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
+	switch version {
+	case VersionTLS10, VersionTLS11:
+		return prf10, crypto.Hash(0)
+	case VersionTLS12:
+		if suite.flags&suiteSHA384 != 0 {
+			return prf12(sha512.New384), crypto.SHA384
+		}
+		return prf12(sha256.New), crypto.SHA256
+	default:
+		panic("unknown version")
+	}
+}
+
+func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
+	prf, _ := prfAndHashForVersion(version, suite)
+	return prf
+}
+
+// masterFromPreMasterSecret generates the master secret from the pre-master
+// secret. See RFC 5246, Section 8.1.
+func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
+	seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
+	seed = append(seed, clientRandom...)
+	seed = append(seed, serverRandom...)
+
+	masterSecret := make([]byte, masterSecretLength)
+	prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
+	return masterSecret
+}
+
+// extMasterFromPreMasterSecret generates the extended master secret from the
+// pre-master secret. See RFC 7627.
+func extMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, transcript []byte) []byte {
+	masterSecret := make([]byte, masterSecretLength)
+	prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, transcript)
+	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) []byte {
+	if (h.version >= VersionTLS12 || sigType == signatureEd25519) && h.buffer == nil {
+		panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer")
+	}
+
+	if sigType == signatureEd25519 {
+		return h.buffer
+	}
+
+	if h.version >= VersionTLS12 {
+		hash := hashAlg.New()
+		hash.Write(h.buffer)
+		return hash.Sum(nil)
+	}
+
+	if sigType == signatureECDSA {
+		return h.server.Sum(nil)
+	}
+
+	return h.Sum()
+}
+
+// discardHandshakeBuffer is called when there is no more need to
+// buffer the entirety of the handshake messages.
+func (h *finishedHash) discardHandshakeBuffer() {
+	h.buffer = nil
+}
+
+// noExportedKeyingMaterial is used as a value of
+// ConnectionState.ekm when renegotiation is enabled and thus
+// we wish to fail all key-material export requests.
+func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
+	return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled")
+}
+
+// ekmFromMasterSecret generates exported keying material as defined in RFC 5705.
+func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) {
+	return func(label string, context []byte, length int) ([]byte, error) {
+		switch label {
+		case "client finished", "server finished", "master secret", "key expansion":
+			// These values are reserved and may not be used.
+			return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label)
+		}
+
+		seedLen := len(serverRandom) + len(clientRandom)
+		if context != nil {
+			seedLen += 2 + len(context)
+		}
+		seed := make([]byte, 0, seedLen)
+
+		seed = append(seed, clientRandom...)
+		seed = append(seed, serverRandom...)
+
+		if context != nil {
+			if len(context) >= 1<<16 {
+				return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long")
+			}
+			seed = append(seed, byte(len(context)>>8), byte(len(context)))
+			seed = append(seed, context...)
+		}
+
+		keyMaterial := make([]byte, length)
+		prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed)
+		return keyMaterial, nil
+	}
+}

+ 427 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/quic.go

@@ -0,0 +1,427 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+	"context"
+	"errors"
+	"fmt"
+)
+
+// QUICEncryptionLevel represents a QUIC encryption level used to transmit
+// handshake messages.
+type QUICEncryptionLevel int
+
+const (
+	QUICEncryptionLevelInitial = QUICEncryptionLevel(iota)
+	QUICEncryptionLevelEarly
+	QUICEncryptionLevelHandshake
+	QUICEncryptionLevelApplication
+)
+
+func (l QUICEncryptionLevel) String() string {
+	switch l {
+	case QUICEncryptionLevelInitial:
+		return "Initial"
+	case QUICEncryptionLevelEarly:
+		return "Early"
+	case QUICEncryptionLevelHandshake:
+		return "Handshake"
+	case QUICEncryptionLevelApplication:
+		return "Application"
+	default:
+		return fmt.Sprintf("QUICEncryptionLevel(%v)", int(l))
+	}
+}
+
+// A QUICConn represents a connection which uses a QUIC implementation as the underlying
+// transport as described in RFC 9001.
+//
+// Methods of QUICConn are not safe for concurrent use.
+type QUICConn struct {
+	conn *Conn
+
+	sessionTicketSent bool
+}
+
+// A QUICConfig configures a QUICConn.
+type QUICConfig struct {
+	TLSConfig *Config
+	// [Psiphon]
+	ExtraConfig *ExtraConfig
+}
+
+// A QUICEventKind is a type of operation on a QUIC connection.
+type QUICEventKind int
+
+const (
+	// QUICNoEvent indicates that there are no events available.
+	QUICNoEvent QUICEventKind = iota
+
+	// QUICSetReadSecret and QUICSetWriteSecret provide the read and write
+	// secrets for a given encryption level.
+	// QUICEvent.Level, QUICEvent.Data, and QUICEvent.Suite are set.
+	//
+	// Secrets for the Initial encryption level are derived from the initial
+	// destination connection ID, and are not provided by the QUICConn.
+	QUICSetReadSecret
+	QUICSetWriteSecret
+
+	// QUICWriteData provides data to send to the peer in CRYPTO frames.
+	// QUICEvent.Data is set.
+	QUICWriteData
+
+	// QUICTransportParameters provides the peer's QUIC transport parameters.
+	// QUICEvent.Data is set.
+	QUICTransportParameters
+
+	// QUICTransportParametersRequired indicates that the caller must provide
+	// QUIC transport parameters to send to the peer. The caller should set
+	// the transport parameters with QUICConn.SetTransportParameters and call
+	// QUICConn.NextEvent again.
+	//
+	// If transport parameters are set before calling QUICConn.Start, the
+	// connection will never generate a QUICTransportParametersRequired event.
+	QUICTransportParametersRequired
+
+	// QUICRejectedEarlyData indicates that the server rejected 0-RTT data even
+	// if we offered it. It's returned before QUICEncryptionLevelApplication
+	// keys are returned.
+	QUICRejectedEarlyData
+
+	// QUICHandshakeDone indicates that the TLS handshake has completed.
+	QUICHandshakeDone
+)
+
+// A QUICEvent is an event occurring on a QUIC connection.
+//
+// The type of event is specified by the Kind field.
+// The contents of the other fields are kind-specific.
+type QUICEvent struct {
+	Kind QUICEventKind
+
+	// Set for QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
+	Level QUICEncryptionLevel
+
+	// Set for QUICTransportParameters, QUICSetReadSecret, QUICSetWriteSecret, and QUICWriteData.
+	// The contents are owned by crypto/tls, and are valid until the next NextEvent call.
+	Data []byte
+
+	// Set for QUICSetReadSecret and QUICSetWriteSecret.
+	Suite uint16
+}
+
+type quicState struct {
+	events    []QUICEvent
+	nextEvent int
+
+	// eventArr is a statically allocated event array, large enough to handle
+	// the usual maximum number of events resulting from a single call: transport
+	// parameters, Initial data, Early read secret, Handshake write and read
+	// secrets, Handshake data, Application write secret, Application data.
+	eventArr [8]QUICEvent
+
+	started  bool
+	signalc  chan struct{}   // handshake data is available to be read
+	blockedc chan struct{}   // handshake is waiting for data, closed when done
+	cancelc  <-chan struct{} // handshake has been canceled
+	cancel   context.CancelFunc
+
+	// readbuf is shared between HandleData and the handshake goroutine.
+	// HandshakeCryptoData passes ownership to the handshake goroutine by
+	// reading from signalc, and reclaims ownership by reading from blockedc.
+	readbuf []byte
+
+	transportParams []byte // to send to the peer
+}
+
+// QUICClient returns a new TLS client side connection using QUICTransport as the
+// underlying transport. The config cannot be nil.
+//
+// The config's MinVersion must be at least TLS 1.3.
+func QUICClient(config *QUICConfig) *QUICConn {
+	return newQUICConn(Client(nil, config.TLSConfig), config.ExtraConfig)
+}
+
+// QUICServer returns a new TLS server side connection using QUICTransport as the
+// underlying transport. The config cannot be nil.
+//
+// The config's MinVersion must be at least TLS 1.3.
+func QUICServer(config *QUICConfig) *QUICConn {
+	return newQUICConn(Server(nil, config.TLSConfig), config.ExtraConfig)
+}
+
+func newQUICConn(conn *Conn, extraConfig *ExtraConfig) *QUICConn {
+	conn.quic = &quicState{
+		signalc:  make(chan struct{}),
+		blockedc: make(chan struct{}),
+	}
+
+	// [Psiphon]
+	conn.extraConfig = extraConfig
+
+	conn.quic.events = conn.quic.eventArr[:0]
+	return &QUICConn{
+		conn: conn,
+	}
+}
+
+// Start starts the client or server handshake protocol.
+// It may produce connection events, which may be read with NextEvent.
+//
+// Start must be called at most once.
+func (q *QUICConn) Start(ctx context.Context) error {
+	if q.conn.quic.started {
+		return quicError(errors.New("tls: Start called more than once"))
+	}
+	q.conn.quic.started = true
+	if q.conn.config.MinVersion < VersionTLS13 {
+		return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13"))
+	}
+	go q.conn.HandshakeContext(ctx)
+	if _, ok := <-q.conn.quic.blockedc; !ok {
+		return q.conn.handshakeErr
+	}
+	return nil
+}
+
+// NextEvent returns the next event occurring on the connection.
+// It returns an event with a Kind of QUICNoEvent when no events are available.
+func (q *QUICConn) NextEvent() QUICEvent {
+	qs := q.conn.quic
+	if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 {
+		// Write over some of the previous event's data,
+		// to catch callers erroniously retaining it.
+		qs.events[last].Data[0] = 0
+	}
+	if qs.nextEvent >= len(qs.events) {
+		qs.events = qs.events[:0]
+		qs.nextEvent = 0
+		return QUICEvent{Kind: QUICNoEvent}
+	}
+	e := qs.events[qs.nextEvent]
+	qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data
+	qs.nextEvent++
+	return e
+}
+
+// Close closes the connection and stops any in-progress handshake.
+func (q *QUICConn) Close() error {
+	if q.conn.quic.cancel == nil {
+		return nil // never started
+	}
+	q.conn.quic.cancel()
+	for range q.conn.quic.blockedc {
+		// Wait for the handshake goroutine to return.
+	}
+	return q.conn.handshakeErr
+}
+
+// HandleData handles handshake bytes received from the peer.
+// It may produce connection events, which may be read with NextEvent.
+func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error {
+	c := q.conn
+	if c.in.level != level {
+		return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level")))
+	}
+	c.quic.readbuf = data
+	<-c.quic.signalc
+	_, ok := <-c.quic.blockedc
+	if ok {
+		// The handshake goroutine is waiting for more data.
+		return nil
+	}
+	// The handshake goroutine has exited.
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	c.hand.Write(c.quic.readbuf)
+	c.quic.readbuf = nil
+	for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil {
+		b := q.conn.hand.Bytes()
+		n := int(b[1])<<16 | int(b[2])<<8 | int(b[3])
+		if n > maxHandshake {
+			q.conn.handshakeErr = fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)
+			break
+		}
+		if len(b) < 4+n {
+			return nil
+		}
+		if err := q.conn.handlePostHandshakeMessage(); err != nil {
+			q.conn.handshakeErr = err
+		}
+	}
+	if q.conn.handshakeErr != nil {
+		return quicError(q.conn.handshakeErr)
+	}
+	return nil
+}
+
+type QUICSessionTicketOptions struct {
+	// EarlyData specifies whether the ticket may be used for 0-RTT.
+	EarlyData bool
+}
+
+// SendSessionTicket sends a session ticket to the client.
+// It produces connection events, which may be read with NextEvent.
+// Currently, it can only be called once.
+func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error {
+	c := q.conn
+	if !c.isHandshakeComplete.Load() {
+		return quicError(errors.New("tls: SendSessionTicket called before handshake completed"))
+	}
+	if c.isClient {
+		return quicError(errors.New("tls: SendSessionTicket called on the client"))
+	}
+	if q.sessionTicketSent {
+		return quicError(errors.New("tls: SendSessionTicket called multiple times"))
+	}
+	q.sessionTicketSent = true
+	return quicError(c.sendSessionTicket(opts.EarlyData))
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (q *QUICConn) ConnectionState() ConnectionState {
+	return q.conn.ConnectionState()
+}
+
+// SetTransportParameters sets the transport parameters to send to the peer.
+//
+// Server connections may delay setting the transport parameters until after
+// receiving the client's transport parameters. See QUICTransportParametersRequired.
+func (q *QUICConn) SetTransportParameters(params []byte) {
+	if params == nil {
+		params = []byte{}
+	}
+	q.conn.quic.transportParams = params
+	if q.conn.quic.started {
+		<-q.conn.quic.signalc
+		<-q.conn.quic.blockedc
+	}
+}
+
+// quicError ensures err is an AlertError.
+// If err is not already, quicError wraps it with alertInternalError.
+func quicError(err error) error {
+	if err == nil {
+		return nil
+	}
+	var ae AlertError
+	if errors.As(err, &ae) {
+		return err
+	}
+	var a alert
+	if !errors.As(err, &a) {
+		a = alertInternalError
+	}
+	// Return an error wrapping the original error and an AlertError.
+	// Truncate the text of the alert to 0 characters.
+	return fmt.Errorf("%w%.0w", err, AlertError(a))
+}
+
+func (c *Conn) quicReadHandshakeBytes(n int) error {
+	for c.hand.Len() < n {
+		if err := c.quicWaitForSignal(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
+	c.quic.events = append(c.quic.events, QUICEvent{
+		Kind:  QUICSetReadSecret,
+		Level: level,
+		Suite: suite,
+		Data:  secret,
+	})
+}
+
+func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) {
+	c.quic.events = append(c.quic.events, QUICEvent{
+		Kind:  QUICSetWriteSecret,
+		Level: level,
+		Suite: suite,
+		Data:  secret,
+	})
+}
+
+func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) {
+	var last *QUICEvent
+	if len(c.quic.events) > 0 {
+		last = &c.quic.events[len(c.quic.events)-1]
+	}
+	if last == nil || last.Kind != QUICWriteData || last.Level != level {
+		c.quic.events = append(c.quic.events, QUICEvent{
+			Kind:  QUICWriteData,
+			Level: level,
+		})
+		last = &c.quic.events[len(c.quic.events)-1]
+	}
+	last.Data = append(last.Data, data...)
+}
+
+func (c *Conn) quicSetTransportParameters(params []byte) {
+	c.quic.events = append(c.quic.events, QUICEvent{
+		Kind: QUICTransportParameters,
+		Data: params,
+	})
+}
+
+func (c *Conn) quicGetTransportParameters() ([]byte, error) {
+	if c.quic.transportParams == nil {
+		c.quic.events = append(c.quic.events, QUICEvent{
+			Kind: QUICTransportParametersRequired,
+		})
+	}
+	for c.quic.transportParams == nil {
+		if err := c.quicWaitForSignal(); err != nil {
+			return nil, err
+		}
+	}
+	return c.quic.transportParams, nil
+}
+
+func (c *Conn) quicHandshakeComplete() {
+	c.quic.events = append(c.quic.events, QUICEvent{
+		Kind: QUICHandshakeDone,
+	})
+}
+
+func (c *Conn) quicRejectedEarlyData() {
+	c.quic.events = append(c.quic.events, QUICEvent{
+		Kind: QUICRejectedEarlyData,
+	})
+}
+
+// quicWaitForSignal notifies the QUICConn that handshake progress is blocked,
+// and waits for a signal that the handshake should proceed.
+//
+// The handshake may become blocked waiting for handshake bytes
+// or for the user to provide transport parameters.
+func (c *Conn) quicWaitForSignal() error {
+	// Drop the handshake mutex while blocked to allow the user
+	// to call ConnectionState before the handshake completes.
+	c.handshakeMutex.Unlock()
+	defer c.handshakeMutex.Lock()
+	// Send on blockedc to notify the QUICConn that the handshake is blocked.
+	// Exported methods of QUICConn wait for the handshake to become blocked
+	// before returning to the user.
+	select {
+	case c.quic.blockedc <- struct{}{}:
+	case <-c.quic.cancelc:
+		return c.sendAlertLocked(alertCloseNotify)
+	}
+	// The QUICConn reads from signalc to notify us that the handshake may
+	// be able to proceed. (The QUICConn reads, because we close signalc to
+	// indicate that the handshake has completed.)
+	select {
+	case c.quic.signalc <- struct{}{}:
+		c.hand.Write(c.quic.readbuf)
+		c.quic.readbuf = nil
+	case <-c.quic.cancelc:
+		return c.sendAlertLocked(alertCloseNotify)
+	}
+	return nil
+}

+ 426 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/ticket.go

@@ -0,0 +1,426 @@
+// 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 (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/sha256"
+	"crypto/subtle"
+	"crypto/tls"
+	"crypto/x509"
+	"errors"
+	"io"
+
+	"golang.org/x/crypto/cryptobyte"
+)
+
+// A sessionState is a resumable session.
+type SessionState = tls.SessionState
+type sessionState struct {
+	// Encoded as a SessionState (in the language of RFC 8446, Section 3).
+	//
+	//   enum { server(1), client(2) } SessionStateType;
+	//
+	//   opaque Certificate<1..2^24-1>;
+	//
+	//   Certificate CertificateChain<0..2^24-1>;
+	//
+	//   opaque Extra<0..2^24-1>;
+	//
+	//   struct {
+	//       uint16 version;
+	//       SessionStateType type;
+	//       uint16 cipher_suite;
+	//       uint64 created_at;
+	//       opaque secret<1..2^8-1>;
+	//       Extra extra<0..2^24-1>;
+	//       uint8 ext_master_secret = { 0, 1 };
+	//       uint8 early_data = { 0, 1 };
+	//       CertificateEntry certificate_list<0..2^24-1>;
+	//       CertificateChain verified_chains<0..2^24-1>; /* excluding leaf */
+	//       select (SessionState.early_data) {
+	//           case 0: Empty;
+	//           case 1: opaque alpn<1..2^8-1>;
+	//       };
+	//       select (SessionState.type) {
+	//           case server: Empty;
+	//           case client: struct {
+	//               select (SessionState.version) {
+	//                   case VersionTLS10..VersionTLS12: Empty;
+	//                   case VersionTLS13: struct {
+	//                       uint64 use_by;
+	//                       uint32 age_add;
+	//                   };
+	//               };
+	//           };
+	//       };
+	//   } SessionState;
+	//
+
+	// Extra is ignored by crypto/tls, but is encoded by [SessionState.Bytes]
+	// and parsed by [ParseSessionState].
+	//
+	// This allows [Config.UnwrapSession]/[Config.WrapSession] and
+	// [ClientSessionCache] implementations to store and retrieve additional
+	// data alongside this session.
+	//
+	// To allow different layers in a protocol stack to share this field,
+	// applications must only append to it, not replace it, and must use entries
+	// that can be recognized even if out of order (for example, by starting
+	// with a id and version prefix).
+	Extra [][]byte
+
+	// EarlyData indicates whether the ticket can be used for 0-RTT in a QUIC
+	// connection. The application may set this to false if it is true to
+	// decline to offer 0-RTT even if supported.
+	EarlyData bool
+
+	version     uint16
+	isClient    bool
+	cipherSuite uint16
+	// createdAt is the generation time of the secret on the sever (which for
+	// TLS 1.0–1.2 might be earlier than the current session) and the time at
+	// which the ticket was received on the client.
+	createdAt         uint64 // seconds since UNIX epoch
+	secret            []byte // master secret for TLS 1.2, or the PSK for TLS 1.3
+	extMasterSecret   bool
+	peerCertificates  []*x509.Certificate
+	activeCertHandles []*activeCert
+	ocspResponse      []byte
+	scts              [][]byte
+	verifiedChains    [][]*x509.Certificate
+	alpnProtocol      string // only set if EarlyData is true
+
+	// Client-side TLS 1.3-only fields.
+	useBy  uint64 // seconds since UNIX epoch
+	ageAdd uint32
+}
+
+// Bytes encodes the session, including any private fields, so that it can be
+// parsed by [ParseSessionState]. The encoding contains secret values critical
+// to the security of future and possibly past sessions.
+//
+// The specific encoding should be considered opaque and may change incompatibly
+// between Go versions.
+func (s *sessionState) Bytes() ([]byte, error) {
+	var b cryptobyte.Builder
+	b.AddUint16(s.version)
+	if s.isClient {
+		b.AddUint8(2) // client
+	} else {
+		b.AddUint8(1) // server
+	}
+	b.AddUint16(s.cipherSuite)
+	addUint64(&b, s.createdAt)
+	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(s.secret)
+	})
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		for _, extra := range s.Extra {
+			b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+				b.AddBytes(extra)
+			})
+		}
+	})
+	if s.extMasterSecret {
+		b.AddUint8(1)
+	} else {
+		b.AddUint8(0)
+	}
+	if s.EarlyData {
+		b.AddUint8(1)
+	} else {
+		b.AddUint8(0)
+	}
+	marshalCertificate(&b, Certificate{
+		Certificate:                 certificatesToBytesSlice(s.peerCertificates),
+		OCSPStaple:                  s.ocspResponse,
+		SignedCertificateTimestamps: s.scts,
+	})
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		for _, chain := range s.verifiedChains {
+			b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+				// We elide the first certificate because it's always the leaf.
+				if len(chain) == 0 {
+					b.SetError(errors.New("tls: internal error: empty verified chain"))
+					return
+				}
+				for _, cert := range chain[1:] {
+					b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+						b.AddBytes(cert.Raw)
+					})
+				}
+			})
+		}
+	})
+	if s.EarlyData {
+		b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+			b.AddBytes([]byte(s.alpnProtocol))
+		})
+	}
+	if s.isClient {
+		if s.version >= VersionTLS13 {
+			addUint64(&b, s.useBy)
+			b.AddUint32(s.ageAdd)
+		}
+	}
+	return b.Bytes()
+}
+
+func certificatesToBytesSlice(certs []*x509.Certificate) [][]byte {
+	s := make([][]byte, 0, len(certs))
+	for _, c := range certs {
+		s = append(s, c.Raw)
+	}
+	return s
+}
+
+// ParseSessionState parses a [SessionState] encoded by [SessionState.Bytes].
+func ParseSessionState(data []byte) (*sessionState, error) {
+	ss := &sessionState{}
+	s := cryptobyte.String(data)
+	var typ, extMasterSecret, earlyData uint8
+	var cert Certificate
+	var extra cryptobyte.String
+	if !s.ReadUint16(&ss.version) ||
+		!s.ReadUint8(&typ) ||
+		(typ != 1 && typ != 2) ||
+		!s.ReadUint16(&ss.cipherSuite) ||
+		!readUint64(&s, &ss.createdAt) ||
+		!readUint8LengthPrefixed(&s, &ss.secret) ||
+		!s.ReadUint24LengthPrefixed(&extra) ||
+		!s.ReadUint8(&extMasterSecret) ||
+		!s.ReadUint8(&earlyData) ||
+		len(ss.secret) == 0 ||
+		!unmarshalCertificate(&s, &cert) {
+		return nil, errors.New("tls: invalid session encoding")
+	}
+	for !extra.Empty() {
+		var e []byte
+		if !readUint24LengthPrefixed(&extra, &e) {
+			return nil, errors.New("tls: invalid session encoding")
+		}
+		ss.Extra = append(ss.Extra, e)
+	}
+	switch extMasterSecret {
+	case 0:
+		ss.extMasterSecret = false
+	case 1:
+		ss.extMasterSecret = true
+	default:
+		return nil, errors.New("tls: invalid session encoding")
+	}
+	switch earlyData {
+	case 0:
+		ss.EarlyData = false
+	case 1:
+		ss.EarlyData = true
+	default:
+		return nil, errors.New("tls: invalid session encoding")
+	}
+	for _, cert := range cert.Certificate {
+		c, err := globalCertCache.newCert(cert)
+		if err != nil {
+			return nil, err
+		}
+		ss.activeCertHandles = append(ss.activeCertHandles, c)
+		ss.peerCertificates = append(ss.peerCertificates, c.cert)
+	}
+	ss.ocspResponse = cert.OCSPStaple
+	ss.scts = cert.SignedCertificateTimestamps
+	var chainList cryptobyte.String
+	if !s.ReadUint24LengthPrefixed(&chainList) {
+		return nil, errors.New("tls: invalid session encoding")
+	}
+	for !chainList.Empty() {
+		var certList cryptobyte.String
+		if !chainList.ReadUint24LengthPrefixed(&certList) {
+			return nil, errors.New("tls: invalid session encoding")
+		}
+		var chain []*x509.Certificate
+		if len(ss.peerCertificates) == 0 {
+			return nil, errors.New("tls: invalid session encoding")
+		}
+		chain = append(chain, ss.peerCertificates[0])
+		for !certList.Empty() {
+			var cert []byte
+			if !readUint24LengthPrefixed(&certList, &cert) {
+				return nil, errors.New("tls: invalid session encoding")
+			}
+			c, err := globalCertCache.newCert(cert)
+			if err != nil {
+				return nil, err
+			}
+			ss.activeCertHandles = append(ss.activeCertHandles, c)
+			chain = append(chain, c.cert)
+		}
+		ss.verifiedChains = append(ss.verifiedChains, chain)
+	}
+	if ss.EarlyData {
+		var alpn []byte
+		if !readUint8LengthPrefixed(&s, &alpn) {
+			return nil, errors.New("tls: invalid session encoding")
+		}
+		ss.alpnProtocol = string(alpn)
+	}
+	if isClient := typ == 2; !isClient {
+		if !s.Empty() {
+			return nil, errors.New("tls: invalid session encoding")
+		}
+		return ss, nil
+	}
+	ss.isClient = true
+	if len(ss.peerCertificates) == 0 {
+		return nil, errors.New("tls: no server certificates in client session")
+	}
+	if ss.version < VersionTLS13 {
+		if !s.Empty() {
+			return nil, errors.New("tls: invalid session encoding")
+		}
+		return ss, nil
+	}
+	if !s.ReadUint64(&ss.useBy) || !s.ReadUint32(&ss.ageAdd) || !s.Empty() {
+		return nil, errors.New("tls: invalid session encoding")
+	}
+	return ss, nil
+}
+
+// sessionState returns a partially filled-out [SessionState] with information
+// from the current connection.
+func (c *Conn) sessionState() (*sessionState, error) {
+	return &sessionState{
+		version:           c.vers,
+		cipherSuite:       c.cipherSuite,
+		createdAt:         uint64(c.config.time().Unix()),
+		alpnProtocol:      c.clientProtocol,
+		peerCertificates:  c.peerCertificates,
+		activeCertHandles: c.activeCertHandles,
+		ocspResponse:      c.ocspResponse,
+		scts:              c.scts,
+		isClient:          c.isClient,
+		extMasterSecret:   c.extMasterSecret,
+		verifiedChains:    c.verifiedChains,
+	}, nil
+}
+
+// EncryptTicket encrypts a ticket with the Config's configured (or default)
+// session ticket keys. It can be used as a [Config.WrapSession] implementation.
+func (c *config) EncryptTicket(cs ConnectionState, ss *sessionState) ([]byte, error) {
+	ticketKeys := c.ticketKeys(nil)
+	stateBytes, err := ss.Bytes()
+	if err != nil {
+		return nil, err
+	}
+	return c.encryptTicket(stateBytes, ticketKeys)
+}
+
+func (c *config) encryptTicket(state []byte, ticketKeys []ticketKey) ([]byte, error) {
+	if len(ticketKeys) == 0 {
+		return nil, errors.New("tls: internal error: session ticket keys unavailable")
+	}
+
+	encrypted := make([]byte, aes.BlockSize+len(state)+sha256.Size)
+	iv := encrypted[:aes.BlockSize]
+	ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
+	authenticated := encrypted[:len(encrypted)-sha256.Size]
+	macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+	if _, err := io.ReadFull(c.rand(), iv); err != nil {
+		return nil, err
+	}
+	key := ticketKeys[0]
+	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(ciphertext, state)
+
+	mac := hmac.New(sha256.New, key.hmacKey[:])
+	mac.Write(authenticated)
+	mac.Sum(macBytes[:0])
+
+	return encrypted, nil
+}
+
+// DecryptTicket decrypts a ticket encrypted by [Config.EncryptTicket]. It can
+// be used as a [Config.UnwrapSession] implementation.
+//
+// If the ticket can't be decrypted or parsed, DecryptTicket returns (nil, nil).
+func (c *config) DecryptTicket(identity []byte, cs ConnectionState) (*sessionState, error) {
+	ticketKeys := c.ticketKeys(nil)
+	stateBytes := c.decryptTicket(identity, ticketKeys)
+	if stateBytes == nil {
+		return nil, nil
+	}
+	s, err := ParseSessionState(stateBytes)
+	if err != nil {
+		return nil, nil // drop unparsable tickets on the floor
+	}
+	return s, nil
+}
+
+func (c *config) decryptTicket(encrypted []byte, ticketKeys []ticketKey) []byte {
+	if len(encrypted) < aes.BlockSize+sha256.Size {
+		return nil
+	}
+
+	iv := encrypted[:aes.BlockSize]
+	ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
+	authenticated := encrypted[:len(encrypted)-sha256.Size]
+	macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+	for _, key := range ticketKeys {
+		mac := hmac.New(sha256.New, key.hmacKey[:])
+		mac.Write(authenticated)
+		expected := mac.Sum(nil)
+
+		if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
+			continue
+		}
+
+		block, err := aes.NewCipher(key.aesKey[:])
+		if err != nil {
+			return nil
+		}
+		plaintext := make([]byte, len(ciphertext))
+		cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
+
+		return plaintext
+	}
+
+	return nil
+}
+
+type ClientSessionState = tls.ClientSessionState
+
+// ClientSessionState contains the state needed by a client to
+// resume a previous TLS session.
+type clientSessionState struct {
+	ticket  []byte
+	session *sessionState
+}
+
+// ResumptionState returns the session ticket sent by the server (also known as
+// the session's identity) and the state necessary to resume this session.
+//
+// It can be called by [ClientSessionCache.Put] to serialize (with
+// [SessionState.Bytes]) and store the session.
+func (cs *clientSessionState) ResumptionState() (ticket []byte, state *sessionState, err error) {
+	return cs.ticket, cs.session, nil
+}
+
+// NewResumptionState returns a state value that can be returned by
+// [ClientSessionCache.Get] to resume a previous session.
+//
+// state needs to be returned by [ParseSessionState], and the ticket and session
+// state must have been returned by [ClientSessionState.ResumptionState].
+func NewResumptionState(ticket []byte, state *sessionState) (*ClientSessionState, error) {
+	cs := &clientSessionState{
+		ticket: ticket, session: state,
+	}
+	return toClientSessionState(cs), nil
+}

+ 356 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/tls.go

@@ -0,0 +1,356 @@
+// 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.
+package tls
+
+// BUG(agl): The crypto/tls package only implements some countermeasures
+// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
+// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
+// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
+
+import (
+	"bytes"
+	"context"
+	"crypto"
+	"crypto/ecdsa"
+	"crypto/ed25519"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"fmt"
+	"net"
+	"os"
+	"strings"
+)
+
+// Server returns a new TLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func Server(conn net.Conn, config *Config) *Conn {
+	c := &Conn{
+		conn:   conn,
+		config: fromConfig(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:   fromConfig(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"))
+		}
+	default:
+		return fail(errors.New("tls: unknown public key algorithm"))
+	}
+
+	return cert, nil
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS #1 private keys by default, while OpenSSL 1.0.0 generates PKCS #8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
+	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+		return key, nil
+	}
+	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+		switch key := key.(type) {
+		case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
+			return key, nil
+		default:
+			return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
+		}
+	}
+	if key, err := x509.ParseECPrivateKey(der); err == nil {
+		return key, nil
+	}
+
+	return nil, errors.New("tls: failed to parse private key")
+}

+ 140 - 0
vendor/github.com/Psiphon-Labs/psiphon-tls/unsafe.go

@@ -0,0 +1,140 @@
+// Code borrowd from https://github.com/quic-go/qtls-go1-20
+
+package tls
+
+import (
+	"crypto/tls"
+	"reflect"
+	"unsafe"
+)
+
+func init() {
+	if !structsEqual(&tls.ConnectionState{}, &connectionState{}) {
+		panic("qtls.ConnectionState doesn't match")
+	}
+	if !structsEqual(&tls.ClientSessionState{}, &clientSessionState{}) {
+		panic("qtls.ClientSessionState doesn't match")
+	}
+	if !structsEqual(&tls.SessionState{}, &sessionState{}) {
+		panic("qtls.SessionState doesn't match")
+	}
+	if !structsEqual(&tls.CertificateRequestInfo{}, &certificateRequestInfo{}) {
+		panic("qtls.CertificateRequestInfo doesn't match")
+	}
+	if !structsEqual(&tls.Config{}, &config{}) {
+		panic("qtls.Config doesn't match")
+	}
+	if !structsEqual(&tls.ClientHelloInfo{}, &clientHelloInfo{}) {
+		panic("qtls.ClientHelloInfo doesn't match")
+	}
+}
+
+func toConnectionState(c connectionState) ConnectionState {
+	return *(*ConnectionState)(unsafe.Pointer(&c))
+}
+
+func toClientSessionState(s *clientSessionState) *ClientSessionState {
+	return (*ClientSessionState)(unsafe.Pointer(s))
+}
+
+func toSessionState(ss *sessionState) *SessionState {
+	return (*SessionState)(unsafe.Pointer(ss))
+}
+
+func fromSessionState(ss *SessionState) *sessionState {
+	return (*sessionState)(unsafe.Pointer(ss))
+}
+
+func fromClientSessionState(s *ClientSessionState) *clientSessionState {
+	return (*clientSessionState)(unsafe.Pointer(s))
+}
+
+func toCertificateRequestInfo(i *certificateRequestInfo) *CertificateRequestInfo {
+	return (*CertificateRequestInfo)(unsafe.Pointer(i))
+}
+
+func toConfig(c *config) *Config {
+	return (*Config)(unsafe.Pointer(c))
+}
+
+func fromConfig(c *Config) *config {
+	return (*config)(unsafe.Pointer(c))
+}
+
+func toClientHelloInfo(chi *clientHelloInfo) *ClientHelloInfo {
+	return (*ClientHelloInfo)(unsafe.Pointer(chi))
+}
+
+func structsEqual(a, b interface{}) bool {
+	return compare(reflect.TypeOf(a), reflect.TypeOf(b))
+}
+
+// compare compares two types and returns true if and only if
+// they can be casted to each other safely.
+// compare does not currently support Maps, Chan, UnsafePointer if reflect.DeepEqual fails.
+// Support for these types can be added if needed.
+// note that field names are still compared.
+func compare(a, b reflect.Type) bool {
+
+	if reflect.DeepEqual(a, b) {
+		return true
+	}
+
+	if a.Kind() != b.Kind() {
+		return false
+	}
+
+	if a.Kind() == reflect.Pointer || a.Kind() == reflect.Slice {
+		return compare(a.Elem(), b.Elem())
+	}
+
+	if a.Kind() == reflect.Func {
+		if a.NumIn() != b.NumIn() || a.NumOut() != b.NumOut() {
+			return false
+		}
+		for i_in := 0; i_in < a.NumIn(); i_in++ {
+			if !compare(a.In(i_in), b.In(i_in)) {
+				return false
+			}
+		}
+		for i_out := 0; i_out < a.NumOut(); i_out++ {
+			if !compare(a.Out(i_out), b.Out(i_out)) {
+				return false
+			}
+		}
+		return true
+	}
+
+	if a.Kind() == reflect.Struct {
+
+		if a.NumField() != b.NumField() {
+			return false
+		}
+
+		for i := 0; i < a.NumField(); i++ {
+			fa := a.Field(i)
+			fb := b.Field(i)
+
+			if !reflect.DeepEqual(fa.Index, fb.Index) || fa.Name != fb.Name ||
+				fa.Anonymous != fb.Anonymous || fa.Offset != fb.Offset {
+				return false
+			}
+
+			if !reflect.DeepEqual(fa.Type, fb.Type) {
+				if !compare(fa.Type, fb.Type) {
+					return false
+				}
+			}
+		}
+
+		return true
+	}
+
+	// TODO: add support for missing types
+	return false
+}
+
+// InitSessionTicketKeys triggers the initialization of session ticket keys.
+func InitSessionTicketKeys(conf *Config) {
+	fromConfig(conf).ticketKeys(nil)
+}

+ 31 - 6
vendor/github.com/Psiphon-Labs/quic-go/framer.go

@@ -23,6 +23,8 @@ type framer interface {
 	Handle0RTTRejection() error
 }
 
+const maxPathResponses = 256
+
 type framerI struct {
 	mutex sync.Mutex
 
@@ -33,6 +35,7 @@ type framerI struct {
 
 	controlFrameMutex sync.Mutex
 	controlFrames     []wire.Frame
+	pathResponses     []*wire.PathResponseFrame
 }
 
 var _ framer = &framerI{}
@@ -52,20 +55,43 @@ func (f *framerI) HasData() bool {
 		return true
 	}
 	f.controlFrameMutex.Lock()
-	hasData = len(f.controlFrames) > 0
-	f.controlFrameMutex.Unlock()
-	return hasData
+	defer f.controlFrameMutex.Unlock()
+	return len(f.controlFrames) > 0 || len(f.pathResponses) > 0
 }
 
 func (f *framerI) QueueControlFrame(frame wire.Frame) {
 	f.controlFrameMutex.Lock()
+	defer f.controlFrameMutex.Unlock()
+
+	if pr, ok := frame.(*wire.PathResponseFrame); ok {
+		// Only queue up to maxPathResponses PATH_RESPONSE frames.
+		// This limit should be high enough to never be hit in practice,
+		// unless the peer is doing something malicious.
+		if len(f.pathResponses) >= maxPathResponses {
+			return
+		}
+		f.pathResponses = append(f.pathResponses, pr)
+		return
+	}
 	f.controlFrames = append(f.controlFrames, frame)
-	f.controlFrameMutex.Unlock()
 }
 
 func (f *framerI) AppendControlFrames(frames []ackhandler.Frame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]ackhandler.Frame, protocol.ByteCount) {
-	var length protocol.ByteCount
 	f.controlFrameMutex.Lock()
+	defer f.controlFrameMutex.Unlock()
+
+	var length protocol.ByteCount
+	// add a PATH_RESPONSE first, but only pack a single PATH_RESPONSE per packet
+	if len(f.pathResponses) > 0 {
+		frame := f.pathResponses[0]
+		frameLen := frame.Length(v)
+		if frameLen <= maxLen {
+			frames = append(frames, ackhandler.Frame{Frame: frame})
+			length += frameLen
+			f.pathResponses = f.pathResponses[1:]
+		}
+	}
+
 	for len(f.controlFrames) > 0 {
 		frame := f.controlFrames[len(f.controlFrames)-1]
 		frameLen := frame.Length(v)
@@ -76,7 +102,6 @@ func (f *framerI) AppendControlFrames(frames []ackhandler.Frame, maxLen protocol
 		length += frameLen
 		f.controlFrames = f.controlFrames[:len(f.controlFrames)-1]
 	}
-	f.controlFrameMutex.Unlock()
 	return frames, length
 }
 

+ 9 - 5
vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/crypto_setup.go

@@ -106,15 +106,19 @@ func NewCryptoSetupClient(
 
 	tlsConf = tlsConf.Clone()
 	tlsConf.MinVersion = tls.VersionTLS13
-	quicConf := &qtls.QUICConfig{TLSConfig: tlsConf}
+	quicConf := &qtls.QUICConfig{
+		TLSConfig: tlsConf,
+
+		// [Psiphon]
+		ExtraConfig: &qtls.ExtraConfig{
+			ClientHelloPRNG:      clientHelloPRNG,
+			GetClientHelloRandom: getClientHelloRandom,
+		},
+	}
 	qtls.SetupConfigForClient(quicConf, cs.marshalDataForSessionState, cs.handleDataFromSessionState)
 	cs.tlsConf = tlsConf
 	cs.allow0RTT = enable0RTT
 
-	// [Psiphon]
-	quicConf.ExtraConfig.ClientHelloPRNG = clientHelloPRNG
-	quicConf.ExtraConfig.GetClientHelloRandom = getClientHelloRandom
-
 	cs.conn = qtls.QUICClient(quicConf)
 	cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient, clientHelloPRNG))
 

+ 6 - 5
vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/cipher_suite_go121.go

@@ -5,9 +5,10 @@ package qtls
 import (
 	"crypto"
 	"crypto/cipher"
-	"crypto/tls"
 	"fmt"
 	"unsafe"
+
+	tls "github.com/Psiphon-Labs/psiphon-tls"
 )
 
 type cipherSuiteTLS13 struct {
@@ -17,16 +18,16 @@ type cipherSuiteTLS13 struct {
 	Hash   crypto.Hash
 }
 
-//go:linkname cipherSuiteTLS13ByID crypto/tls.cipherSuiteTLS13ByID
+//go:linkname cipherSuiteTLS13ByID github.com/Psiphon-Labs/psiphon-tls.cipherSuiteTLS13ByID
 func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13
 
-//go:linkname cipherSuitesTLS13 crypto/tls.cipherSuitesTLS13
+//go:linkname cipherSuitesTLS13 github.com/Psiphon-Labs/psiphon-tls.cipherSuitesTLS13
 var cipherSuitesTLS13 []unsafe.Pointer
 
-//go:linkname defaultCipherSuitesTLS13 crypto/tls.defaultCipherSuitesTLS13
+//go:linkname defaultCipherSuitesTLS13 github.com/Psiphon-Labs/psiphon-tls.defaultCipherSuitesTLS13
 var defaultCipherSuitesTLS13 []uint16
 
-//go:linkname defaultCipherSuitesTLS13NoAES crypto/tls.defaultCipherSuitesTLS13NoAES
+//go:linkname defaultCipherSuitesTLS13NoAES github.com/Psiphon-Labs/psiphon-tls.defaultCipherSuitesTLS13NoAES
 var defaultCipherSuitesTLS13NoAES []uint16
 
 var cipherSuitesModified bool

+ 2 - 4
vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go120.go

@@ -54,10 +54,8 @@ func SetupConfigForServer(conf *QUICConfig, enable0RTT bool, getDataForSessionTi
 }
 
 func SetupConfigForClient(conf *QUICConfig, getDataForSessionState func() []byte, setDataFromSessionState func([]byte) bool) {
-	conf.ExtraConfig = &qtls.ExtraConfig{
-		GetAppDataForSessionState:  getDataForSessionState,
-		SetAppDataFromSessionState: setDataFromSessionState,
-	}
+	conf.ExtraConfig.GetAppDataForSessionState = getDataForSessionState
+	conf.ExtraConfig.SetAppDataFromSessionState = setDataFromSessionState
 }
 
 func QUICServer(config *QUICConfig) *QUICConn {

+ 8 - 1
vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go121.go

@@ -4,15 +4,16 @@ package qtls
 
 import (
 	"bytes"
-	"crypto/tls"
 	"fmt"
 
+	tls "github.com/Psiphon-Labs/psiphon-tls"
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 )
 
 type (
 	QUICConn                 = tls.QUICConn
 	QUICConfig               = tls.QUICConfig
+	ExtraConfig              = tls.ExtraConfig
 	QUICEvent                = tls.QUICEvent
 	QUICEventKind            = tls.QUICEventKind
 	QUICEncryptionLevel      = tls.QUICEncryptionLevel
@@ -157,3 +158,9 @@ func SendSessionTicket(c *QUICConn, allow0RTT bool) error {
 		EarlyData: allow0RTT,
 	})
 }
+
+// [Psiphon]
+
+func ReadClientHelloRandom(data []byte) ([]byte, error) {
+	return tls.ReadClientHelloRandom(data)
+}

+ 7 - 1
vendor/github.com/Psiphon-Labs/quic-go/packet_packer.go

@@ -640,7 +640,13 @@ func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount, onlyAc
 		pl.length += lengthAdded
 		// add handlers for the control frames that were added
 		for i := startLen; i < len(pl.frames); i++ {
-			pl.frames[i].Handler = p.retransmissionQueue.AppDataAckHandler()
+			switch pl.frames[i].Frame.(type) {
+			case *wire.PathChallengeFrame, *wire.PathResponseFrame:
+				// Path probing is currently not supported, therefore we don't need to set the OnAcked callback yet.
+				// PATH_CHALLENGE and PATH_RESPONSE are never retransmitted.
+			default:
+				pl.frames[i].Handler = p.retransmissionQueue.AppDataAckHandler()
+			}
 		}
 
 		pl.streamFrames, lengthAdded = p.framer.AppendStreamFrames(pl.streamFrames, maxFrameSize-pl.length, v)

+ 4 - 1
vendor/modules.txt

@@ -20,10 +20,13 @@ github.com/Psiphon-Labs/bolt
 # github.com/Psiphon-Labs/goptlib v0.0.0-20200406165125-c0e32a7a3464
 ## explicit
 github.com/Psiphon-Labs/goptlib
+# github.com/Psiphon-Labs/psiphon-tls v0.0.0-20240129160049-e465a08acc16
+## explicit; go 1.20
+github.com/Psiphon-Labs/psiphon-tls
 # github.com/Psiphon-Labs/qtls-go1-20 v0.0.0-20231117202359-5544003bda6f
 ## explicit; go 1.20
 github.com/Psiphon-Labs/qtls-go1-20
-# github.com/Psiphon-Labs/quic-go v0.0.0-20231117205605-756d3e334a3b
+# github.com/Psiphon-Labs/quic-go v0.0.0-20240130155801-3197a7943511
 ## explicit; go 1.20
 github.com/Psiphon-Labs/quic-go
 github.com/Psiphon-Labs/quic-go/http3