Răsfoiți Sursa

Update vendored quic-go

- Supports up to IETF draft-34
- Still default to using IETF draft-29
Rod Hynes 4 ani în urmă
părinte
comite
e5058296d5
100 a modificat fișierele cu 2944 adăugiri și 1977 ștergeri
  1. 6 6
      psiphon/common/quic/quic.go
  2. 4 2
      vendor/github.com/Psiphon-Labs/qtls-go1-15/handshake_client.go
  3. 2 2
      vendor/github.com/Psiphon-Labs/qtls-go1-15/handshake_client_tls13.go
  4. 3 4
      vendor/github.com/Psiphon-Labs/qtls-go1-15/handshake_messages.go
  5. 3 2
      vendor/github.com/Psiphon-Labs/qtls-go1-15/handshake_server_tls13.go
  6. 0 0
      vendor/github.com/Psiphon-Labs/qtls-go1-16/LICENSE
  7. 0 0
      vendor/github.com/Psiphon-Labs/qtls-go1-16/README.md
  8. 102 0
      vendor/github.com/Psiphon-Labs/qtls-go1-16/alert.go
  9. 5 13
      vendor/github.com/Psiphon-Labs/qtls-go1-16/auth.go
  10. 19 40
      vendor/github.com/Psiphon-Labs/qtls-go1-16/cipher_suites.go
  11. 373 245
      vendor/github.com/Psiphon-Labs/qtls-go1-16/common.go
  12. 146 88
      vendor/github.com/Psiphon-Labs/qtls-go1-16/conn.go
  13. 3 4
      vendor/github.com/Psiphon-Labs/qtls-go1-16/go.mod
  14. 2 5
      vendor/github.com/Psiphon-Labs/qtls-go1-16/go.sum
  15. 146 91
      vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_client.go
  16. 85 56
      vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_client_tls13.go
  17. 3 4
      vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_messages.go
  18. 109 42
      vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_server.go
  19. 45 12
      vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_server_tls13.go
  20. 9 9
      vendor/github.com/Psiphon-Labs/qtls-go1-16/key_agreement.go
  21. 2 5
      vendor/github.com/Psiphon-Labs/qtls-go1-16/key_schedule.go
  22. 0 0
      vendor/github.com/Psiphon-Labs/qtls-go1-16/prf.go
  23. 52 78
      vendor/github.com/Psiphon-Labs/qtls-go1-16/ticket.go
  24. 112 29
      vendor/github.com/Psiphon-Labs/qtls-go1-16/tls.go
  25. 96 0
      vendor/github.com/Psiphon-Labs/qtls-go1-16/unsafe.go
  26. 0 90
      vendor/github.com/Psiphon-Labs/qtls/alert.go
  27. 4 0
      vendor/github.com/Psiphon-Labs/quic-go/Changelog.md
  28. 4 4
      vendor/github.com/Psiphon-Labs/quic-go/README.md
  29. 2 2
      vendor/github.com/Psiphon-Labs/quic-go/buffer_pool.go
  30. 12 12
      vendor/github.com/Psiphon-Labs/quic-go/client.go
  31. 0 1
      vendor/github.com/Psiphon-Labs/quic-go/codecov.yml
  32. 41 23
      vendor/github.com/Psiphon-Labs/quic-go/config.go
  33. 11 6
      vendor/github.com/Psiphon-Labs/quic-go/conn.go
  34. 0 113
      vendor/github.com/Psiphon-Labs/quic-go/conn_ecn.go
  35. 4 2
      vendor/github.com/Psiphon-Labs/quic-go/conn_generic.go
  36. 9 7
      vendor/github.com/Psiphon-Labs/quic-go/conn_helper_darwin.go
  37. 17 0
      vendor/github.com/Psiphon-Labs/quic-go/conn_helper_freebsd.go
  38. 11 5
      vendor/github.com/Psiphon-Labs/quic-go/conn_helper_linux.go
  39. 1 1
      vendor/github.com/Psiphon-Labs/quic-go/conn_id_generator.go
  40. 4 11
      vendor/github.com/Psiphon-Labs/quic-go/conn_id_manager.go
  41. 235 0
      vendor/github.com/Psiphon-Labs/quic-go/conn_oob.go
  42. 3 1
      vendor/github.com/Psiphon-Labs/quic-go/conn_windows.go
  43. 87 0
      vendor/github.com/Psiphon-Labs/quic-go/datagram_queue.go
  44. 31 2
      vendor/github.com/Psiphon-Labs/quic-go/framer.go
  45. 4 8
      vendor/github.com/Psiphon-Labs/quic-go/go.mod
  46. 13 41
      vendor/github.com/Psiphon-Labs/quic-go/go.sum
  47. 82 23
      vendor/github.com/Psiphon-Labs/quic-go/http3/client.go
  48. 3 0
      vendor/github.com/Psiphon-Labs/quic-go/http3/error_codes.go
  49. 48 21
      vendor/github.com/Psiphon-Labs/quic-go/http3/frames.go
  50. 45 15
      vendor/github.com/Psiphon-Labs/quic-go/http3/response_writer.go
  51. 12 5
      vendor/github.com/Psiphon-Labs/quic-go/http3/roundtrip.go
  52. 107 26
      vendor/github.com/Psiphon-Labs/quic-go/http3/server.go
  53. 52 18
      vendor/github.com/Psiphon-Labs/quic-go/interface.go
  54. 2 3
      vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/ackhandler.go
  55. 3 4
      vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/interfaces.go
  56. 45 30
      vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/packet_number_generator.go
  57. 1 3
      vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/received_packet_handler.go
  58. 4 8
      vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/received_packet_history.go
  59. 112 118
      vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/sent_packet_handler.go
  60. 3 2
      vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/sent_packet_history.go
  61. 2 0
      vendor/github.com/Psiphon-Labs/quic-go/internal/congestion/cubic.go
  62. 69 36
      vendor/github.com/Psiphon-Labs/quic-go/internal/congestion/cubic_sender.go
  63. 1 0
      vendor/github.com/Psiphon-Labs/quic-go/internal/congestion/interface.go
  64. 22 13
      vendor/github.com/Psiphon-Labs/quic-go/internal/congestion/pacer.go
  65. 1 2
      vendor/github.com/Psiphon-Labs/quic-go/internal/flowcontrol/base_flow_controller.go
  66. 16 0
      vendor/github.com/Psiphon-Labs/quic-go/internal/flowcontrol/connection_flow_controller.go
  67. 1 0
      vendor/github.com/Psiphon-Labs/quic-go/internal/flowcontrol/interface.go
  68. 21 8
      vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/crypto_setup.go
  69. 15 5
      vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/initial_aead.go
  70. 20 8
      vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/retry.go
  71. 5 5
      vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/session_ticket.go
  72. 17 7
      vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/tls_extension_handler.go
  73. 4 0
      vendor/github.com/Psiphon-Labs/quic-go/internal/logutils/frame.go
  74. 3 3
      vendor/github.com/Psiphon-Labs/quic-go/internal/protocol/connection_id.go
  75. 32 16
      vendor/github.com/Psiphon-Labs/quic-go/internal/protocol/params.go
  76. 6 3
      vendor/github.com/Psiphon-Labs/quic-go/internal/protocol/protocol.go
  77. 4 1
      vendor/github.com/Psiphon-Labs/quic-go/internal/protocol/version.go
  78. 15 5
      vendor/github.com/Psiphon-Labs/quic-go/internal/qerr/quic_error.go
  79. 0 190
      vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go114.go
  80. 1 0
      vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go115.go
  81. 114 0
      vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go116.go
  82. 0 219
      vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/qtls.go
  83. 0 21
      vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/structs_equal.go
  84. 29 0
      vendor/github.com/Psiphon-Labs/quic-go/internal/utils/rand.go
  85. 27 26
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/ack_frame.go
  86. 9 9
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/connection_close_frame.go
  87. 8 8
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/crypto_frame.go
  88. 4 4
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/data_blocked_frame.go
  89. 85 0
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/datagram_frame.go
  90. 4 3
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/extended_header.go
  91. 13 2
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/frame_parser.go
  92. 19 2
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/header.go
  93. 4 4
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/max_data_frame.go
  94. 6 6
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/max_stream_data_frame.go
  95. 4 4
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/max_streams_frame.go
  96. 6 7
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/new_connection_id_frame.go
  97. 4 4
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/new_token_frame.go
  98. 2 2
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/pool.go
  99. 8 8
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/reset_stream_frame.go
  100. 4 4
      vendor/github.com/Psiphon-Labs/quic-go/internal/wire/retire_connection_id_frame.go

+ 6 - 6
psiphon/common/quic/quic.go

@@ -91,7 +91,7 @@ var supportedVersionNumbers = map[string]uint32{
 
 func isObfuscated(quicVersion string) bool {
 	return quicVersion == protocol.QUIC_VERSION_OBFUSCATED ||
-		quicVersion == QUIC_VERSION_OBFUSCATED_IETF29
+		quicVersion == protocol.QUIC_VERSION_OBFUSCATED_IETF29
 }
 
 func isClientHelloRandomized(quicVersion string) bool {
@@ -739,9 +739,9 @@ func dialQUIC(
 
 	if isIETFVersion(versionNumber) {
 		quicConfig := &ietf_quic.Config{
-			HandshakeTimeout: time.Duration(1<<63 - 1),
-			MaxIdleTimeout:   CLIENT_IDLE_TIMEOUT,
-			KeepAlive:        true,
+			HandshakeIdleTimeout: time.Duration(1<<63 - 1),
+			MaxIdleTimeout:       CLIENT_IDLE_TIMEOUT,
+			KeepAlive:            true,
 			Versions: []ietf_quic.VersionNumber{
 				ietf_quic.VersionNumber(versionNumber)},
 			ClientHelloSeed: clientHelloSeed,
@@ -749,7 +749,7 @@ func dialQUIC(
 
 		deadline, ok := ctx.Deadline()
 		if ok {
-			quicConfig.HandshakeTimeout = time.Until(deadline)
+			quicConfig.HandshakeIdleTimeout = time.Until(deadline)
 		}
 
 		var dialSession ietf_quic.Session
@@ -961,7 +961,7 @@ func newMuxListener(
 	}
 
 	ietfQUICConfig := &ietf_quic.Config{
-		HandshakeTimeout:      SERVER_HANDSHAKE_TIMEOUT,
+		HandshakeIdleTimeout:  SERVER_HANDSHAKE_TIMEOUT,
 		MaxIdleTimeout:        serverIdleTimeout,
 		MaxIncomingStreams:    1,
 		MaxIncomingUniStreams: -1,

+ 4 - 2
vendor/github.com/Psiphon-Labs/qtls-go1-15/handshake_client.go

@@ -89,9 +89,11 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
 		secureRenegotiationSupported: true,
 		alpnProtocols:                config.NextProtos,
 		supportedVersions:            supportedVersions,
+	}
 
-		// [Psiphon]
-		PRNG: c.extraConfig.ClientHelloPRNG,
+	// [Psiphon]
+	if c.extraConfig != nil {
+		hello.PRNG = c.extraConfig.ClientHelloPRNG
 	}
 
 	if c.handshakes > 0 {

+ 2 - 2
vendor/github.com/Psiphon-Labs/qtls-go1-15/handshake_client_tls13.go

@@ -262,10 +262,10 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
 		}
 	}
 
-	hs.hello.earlyData = false // disable 0-RTT
-	if c.extraConfig != nil && c.extraConfig.Rejected0RTT != nil {
+	if hs.hello.earlyData && c.extraConfig != nil && c.extraConfig.Rejected0RTT != nil {
 		c.extraConfig.Rejected0RTT()
 	}
+	hs.hello.earlyData = false // disable 0-RTT
 
 	hs.transcript.Write(hs.hello.marshal())
 	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {

+ 3 - 4
vendor/github.com/Psiphon-Labs/qtls-go1-15/handshake_messages.go

@@ -100,6 +100,9 @@ type clientHelloMsg struct {
 }
 
 func (m *clientHelloMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
 
 	// [Psiphon]
 	// Randomize the Client Hello.
@@ -107,10 +110,6 @@ func (m *clientHelloMsg) marshal() []byte {
 		return m.marshalRandomized()
 	}
 
-	if m.raw != nil {
-		return m.raw
-	}
-
 	var b cryptobyte.Builder
 	b.AddUint8(typeClientHello)
 	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {

+ 3 - 2
vendor/github.com/Psiphon-Labs/qtls-go1-15/handshake_server_tls13.go

@@ -284,7 +284,8 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
 			}
 
 			if sessionState.alpn == c.clientProtocol &&
-				c.extraConfig != nil && c.extraConfig.Accept0RTT != nil && c.extraConfig.Accept0RTT(sessionState.appData) {
+				c.extraConfig != nil && c.extraConfig.MaxEarlyData > 0 &&
+				c.extraConfig.Accept0RTT != nil && c.extraConfig.Accept0RTT(sessionState.appData) {
 				hs.encryptedExtensions.earlyData = true
 				c.used0RTT = true
 			}
@@ -340,7 +341,7 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
 
 		h := cloneHash(hs.transcript, hs.suite.hash)
 		h.Write(hs.clientHello.marshal())
-		if sessionState.maxEarlyData > 0 && c.extraConfig != nil && c.extraConfig.MaxEarlyData > 0 {
+		if hs.encryptedExtensions.earlyData {
 			clientEarlySecret := hs.suite.deriveSecret(hs.earlySecret, "c e traffic", h)
 			c.in.exportKey(Encryption0RTT, hs.suite, clientEarlySecret)
 			if err := c.config.writeKeyLog(keyLogLabelEarlyTraffic, hs.clientHello.random, clientEarlySecret); err != nil {

+ 0 - 0
vendor/github.com/Psiphon-Labs/qtls/LICENSE → vendor/github.com/Psiphon-Labs/qtls-go1-16/LICENSE


+ 0 - 0
vendor/github.com/Psiphon-Labs/qtls/README.md → vendor/github.com/Psiphon-Labs/qtls-go1-16/README.md


+ 102 - 0
vendor/github.com/Psiphon-Labs/qtls-go1-16/alert.go

@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package qtls
+
+import "strconv"
+
+type alert uint8
+
+// Alert is a TLS alert
+type Alert = alert
+
+const (
+	// alert level
+	alertLevelWarning = 1
+	alertLevelError   = 2
+)
+
+const (
+	alertCloseNotify                  alert = 0
+	alertUnexpectedMessage            alert = 10
+	alertBadRecordMAC                 alert = 20
+	alertDecryptionFailed             alert = 21
+	alertRecordOverflow               alert = 22
+	alertDecompressionFailure         alert = 30
+	alertHandshakeFailure             alert = 40
+	alertBadCertificate               alert = 42
+	alertUnsupportedCertificate       alert = 43
+	alertCertificateRevoked           alert = 44
+	alertCertificateExpired           alert = 45
+	alertCertificateUnknown           alert = 46
+	alertIllegalParameter             alert = 47
+	alertUnknownCA                    alert = 48
+	alertAccessDenied                 alert = 49
+	alertDecodeError                  alert = 50
+	alertDecryptError                 alert = 51
+	alertExportRestriction            alert = 60
+	alertProtocolVersion              alert = 70
+	alertInsufficientSecurity         alert = 71
+	alertInternalError                alert = 80
+	alertInappropriateFallback        alert = 86
+	alertUserCanceled                 alert = 90
+	alertNoRenegotiation              alert = 100
+	alertMissingExtension             alert = 109
+	alertUnsupportedExtension         alert = 110
+	alertCertificateUnobtainable      alert = 111
+	alertUnrecognizedName             alert = 112
+	alertBadCertificateStatusResponse alert = 113
+	alertBadCertificateHashValue      alert = 114
+	alertUnknownPSKIdentity           alert = 115
+	alertCertificateRequired          alert = 116
+	alertNoApplicationProtocol        alert = 120
+)
+
+var alertText = map[alert]string{
+	alertCloseNotify:                  "close notify",
+	alertUnexpectedMessage:            "unexpected message",
+	alertBadRecordMAC:                 "bad record MAC",
+	alertDecryptionFailed:             "decryption failed",
+	alertRecordOverflow:               "record overflow",
+	alertDecompressionFailure:         "decompression failure",
+	alertHandshakeFailure:             "handshake failure",
+	alertBadCertificate:               "bad certificate",
+	alertUnsupportedCertificate:       "unsupported certificate",
+	alertCertificateRevoked:           "revoked certificate",
+	alertCertificateExpired:           "expired certificate",
+	alertCertificateUnknown:           "unknown certificate",
+	alertIllegalParameter:             "illegal parameter",
+	alertUnknownCA:                    "unknown certificate authority",
+	alertAccessDenied:                 "access denied",
+	alertDecodeError:                  "error decoding message",
+	alertDecryptError:                 "error decrypting message",
+	alertExportRestriction:            "export restriction",
+	alertProtocolVersion:              "protocol version not supported",
+	alertInsufficientSecurity:         "insufficient security level",
+	alertInternalError:                "internal error",
+	alertInappropriateFallback:        "inappropriate fallback",
+	alertUserCanceled:                 "user canceled",
+	alertNoRenegotiation:              "no renegotiation",
+	alertMissingExtension:             "missing extension",
+	alertUnsupportedExtension:         "unsupported extension",
+	alertCertificateUnobtainable:      "certificate unobtainable",
+	alertUnrecognizedName:             "unrecognized name",
+	alertBadCertificateStatusResponse: "bad certificate status response",
+	alertBadCertificateHashValue:      "bad certificate hash value",
+	alertUnknownPSKIdentity:           "unknown PSK identity",
+	alertCertificateRequired:          "certificate required",
+	alertNoApplicationProtocol:        "no application protocol",
+}
+
+func (e alert) String() string {
+	s, ok := alertText[e]
+	if ok {
+		return "tls: " + s
+	}
+	return "tls: alert(" + strconv.Itoa(int(e)) + ")"
+}
+
+func (e alert) Error() string {
+	return e.String()
+}

+ 5 - 13
vendor/github.com/Psiphon-Labs/qtls/auth.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/auth.go

@@ -11,7 +11,6 @@ import (
 	"crypto/ed25519"
 	"crypto/elliptic"
 	"crypto/rsa"
-	"encoding/asn1"
 	"errors"
 	"fmt"
 	"hash"
@@ -27,14 +26,7 @@ func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc c
 		if !ok {
 			return fmt.Errorf("expected an ECDSA public key, got %T", pubkey)
 		}
-		ecdsaSig := new(ecdsaSignature)
-		if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
-			return err
-		}
-		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
-			return errors.New("ECDSA signature contained zero or negative values")
-		}
-		if !ecdsa.Verify(pubKey, signed, ecdsaSig.R, ecdsaSig.S) {
+		if !ecdsa.VerifyASN1(pubKey, signed, sig) {
 			return errors.New("ECDSA verification failure")
 		}
 	case signatureEd25519:
@@ -114,7 +106,7 @@ func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType
 	case Ed25519:
 		sigType = signatureEd25519
 	default:
-		return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
+		return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
 	}
 	switch signatureAlgorithm {
 	case PKCS1WithSHA1, ECDSAWithSHA1:
@@ -128,7 +120,7 @@ func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType
 	case Ed25519:
 		hash = directSigning
 	default:
-		return 0, 0, fmt.Errorf("unsupported signature algorithm: %#04x", signatureAlgorithm)
+		return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
 	}
 	return sigType, hash, nil
 }
@@ -163,9 +155,9 @@ var rsaSignatureSchemes = []struct {
 	{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
+	// 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.
+	// 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},

+ 19 - 40
vendor/github.com/Psiphon-Labs/qtls/cipher_suites.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/cipher_suites.go

@@ -116,15 +116,15 @@ type keyAgreement interface {
 	// 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)
+	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)
+	processServerKeyExchange(*config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
+	generateClientKeyExchange(*config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
 }
 
 const (
@@ -160,7 +160,7 @@ type cipherSuite struct {
 	// flags is a bitmask of the suite* values, above.
 	flags  int
 	cipher func(key, iv []byte, isRead bool) interface{}
-	mac    func(version uint16, macKey []byte) macFunction
+	mac    func(key []byte) hash.Hash
 	aead   func(key, fixedNonce []byte) aead
 }
 
@@ -258,24 +258,15 @@ func cipherAES(key, iv []byte, isRead bool) interface{} {
 	return cipher.NewCBCEncrypter(block, iv)
 }
 
-// macSHA1 returns a macFunction for the given protocol version.
-func macSHA1(version uint16, key []byte) macFunction {
-	return tls10MAC{h: hmac.New(newConstantTimeHash(sha1.New), key)}
+// macSHA1 returns a SHA-1 based constant time MAC.
+func macSHA1(key []byte) hash.Hash {
+	return hmac.New(newConstantTimeHash(sha1.New), key)
 }
 
-// macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2
-// so the given version is ignored.
-func macSHA256(version uint16, key []byte) macFunction {
-	return tls10MAC{h: hmac.New(sha256.New, key)}
-}
-
-type macFunction interface {
-	// Size returns the length of the MAC.
-	Size() int
-	// MAC appends the MAC of (seq, header, data) to out. The extra data is fed
-	// into the MAC after obtaining the result to normalize timing. The result
-	// is only valid until the next invocation of MAC as the buffer is reused.
-	MAC(seq, header, data, extra []byte) []byte
+// macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and
+// is currently only used in disabled-by-default cipher suites.
+func macSHA256(key []byte) hash.Hash {
+	return hmac.New(sha256.New, key)
 }
 
 type aead interface {
@@ -428,26 +419,14 @@ func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
 }
 
 // tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
-type tls10MAC struct {
-	h   hash.Hash
-	buf []byte
-}
-
-func (s tls10MAC) Size() int {
-	return s.h.Size()
-}
-
-// MAC is guaranteed to take constant time, as long as
-// len(seq)+len(header)+len(data)+len(extra) is constant. extra is not fed into
-// the MAC, but is only provided to make the timing profile constant.
-func (s tls10MAC) MAC(seq, header, data, extra []byte) []byte {
-	s.h.Reset()
-	s.h.Write(seq)
-	s.h.Write(header)
-	s.h.Write(data)
-	res := s.h.Sum(s.buf[:0])
+func tls10MAC(h hash.Hash, out, seq, header, data, extra []byte) []byte {
+	h.Reset()
+	h.Write(seq)
+	h.Write(header)
+	h.Write(data)
+	res := h.Sum(out)
 	if extra != nil {
-		s.h.Write(extra)
+		h.Write(extra)
 	}
 	return res
 }

+ 373 - 245
vendor/github.com/Psiphon-Labs/qtls/common.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/common.go

@@ -19,8 +19,9 @@ import (
 	"errors"
 	"fmt"
 	"io"
-	"math/big"
 	"net"
+	"runtime"
+	"sort"
 	"strings"
 	"sync"
 	"time"
@@ -220,51 +221,94 @@ const (
 	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
+
+type ConnectionState = tls.ConnectionState
+
 // ConnectionState records basic TLS details about the connection.
-type ConnectionState struct {
-	Version                     uint16                // TLS version used by the connection (e.g. VersionTLS12)
-	HandshakeComplete           bool                  // TLS handshake is complete
-	DidResume                   bool                  // connection resumes a previous TLS connection
-	CipherSuite                 uint16                // cipher suite in use (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ...)
-	NegotiatedProtocol          string                // negotiated next protocol (not guaranteed to be from Config.NextProtos)
-	NegotiatedProtocolIsMutual  bool                  // negotiated protocol was advertised by server (client side only)
-	ServerName                  string                // server name requested by client, if any (server side only)
-	PeerCertificates            []*x509.Certificate   // certificate chain presented by remote peer
-	VerifiedChains              [][]*x509.Certificate // verified chains built from PeerCertificates
-	SignedCertificateTimestamps [][]byte              // SCTs from the peer, if any
-	OCSPResponse                []byte                // stapled OCSP response from peer, if any
+type connectionState struct {
+	// Version is the TLS version used by the connection (e.g. VersionTLS12).
+	Version uint16
 
-	Used0RTT bool // true if 0-RTT was both offered and accepted
+	// HandshakeComplete is true if the handshake has concluded.
+	HandshakeComplete bool
 
-	// ekm is a closure exposed via ExportKeyingMaterial.
-	ekm func(label string, context []byte, length int) ([]byte, error)
+	// DidResume is true if this connection was successfully resumed from a
+	// previous session with a session ticket or similar mechanism.
+	DidResume bool
+
+	// CipherSuite is the cipher suite negotiated for the connection (e.g.
+	// TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256).
+	CipherSuite uint16
+
+	// NegotiatedProtocol is the application protocol negotiated with ALPN.
+	NegotiatedProtocol string
+
+	// NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation.
+	//
+	// Deprecated: this value is always true.
+	NegotiatedProtocolIsMutual bool
+
+	// ServerName is the value of the Server Name Indication extension sent by
+	// the client. It's available both on the server and on the client side.
+	ServerName string
+
+	// PeerCertificates are the parsed certificates sent by the peer, in the
+	// order in which they were sent. The first element is the leaf certificate
+	// that the connection is verified against.
+	//
+	// On the client side, it can't be empty. On the server side, it can be
+	// empty if Config.ClientAuth is not RequireAnyClientCert or
+	// RequireAndVerifyClientCert.
+	PeerCertificates []*x509.Certificate
+
+	// VerifiedChains is a list of one or more chains where the first element is
+	// PeerCertificates[0] and the last element is from Config.RootCAs (on the
+	// client side) or Config.ClientCAs (on the server side).
+	//
+	// On the client side, it's set if Config.InsecureSkipVerify is false. On
+	// the server side, it's set if Config.ClientAuth is VerifyClientCertIfGiven
+	// (and the peer provided a certificate) or RequireAndVerifyClientCert.
+	VerifiedChains [][]*x509.Certificate
+
+	// 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). For resumed sessions this value will be nil
-	// because resumption does not include enough context (see
-	// https://mitls.org/pages/attacks/3SHAKE#channelbindings). This will
-	// change in future versions of Go once the TLS master-secret fix has
-	// been standardized and implemented. It is not defined in TLS 1.3.
+	// TLSUnique contains the "tls-unique" channel binding value (see RFC 5929,
+	// Section 3). This value will be nil for TLS 1.3 connections and for all
+	// resumed connections.
+	//
+	// Deprecated: there are conditions in which this value might not be unique
+	// to a connection. See the Security Considerations sections of RFC 5705 and
+	// RFC 7627, and https://mitls.org/pages/attacks/3SHAKE#channelbindings.
 	TLSUnique []byte
+
+	// ekm is a closure exposed via ExportKeyingMaterial.
+	ekm func(label string, context []byte, length int) ([]byte, error)
 }
 
-// ExportKeyingMaterial returns length bytes of exported key material in a new
-// slice as defined in RFC 5705. If context is nil, it is not used as part of
-// the seed. If the connection was set to allow renegotiation via
-// Config.Renegotiation, this function will return an error.
-func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
-	return cs.ekm(label, context, length)
+type ConnectionStateWith0RTT struct {
+	ConnectionState
+
+	Used0RTT bool // true if 0-RTT was both offered and accepted
 }
 
 // ClientAuthType is tls.ClientAuthType
 type ClientAuthType = tls.ClientAuthType
 
 const (
-	NoClientCert ClientAuthType = iota
-	RequestClientCert
-	RequireAnyClientCert
-	VerifyClientCertIfGiven
-	RequireAndVerifyClientCert
+	NoClientCert               = tls.NoClientCert
+	RequestClientCert          = tls.RequestClientCert
+	RequireAnyClientCert       = tls.RequireAnyClientCert
+	VerifyClientCertIfGiven    = tls.VerifyClientCertIfGiven
+	RequireAndVerifyClientCert = tls.RequireAndVerifyClientCert
 )
 
 // requiresClientCert reports whether the ClientAuthType requires a client
@@ -280,7 +324,9 @@ func requiresClientCert(c ClientAuthType) bool {
 
 // ClientSessionState contains the state needed by clients to resume TLS
 // sessions.
-type ClientSessionState struct {
+type ClientSessionState = tls.ClientSessionState
+
+type clientSessionState struct {
 	sessionTicket      []uint8               // Encrypted ticket used for session resumption with server
 	vers               uint16                // TLS version negotiated for the session
 	cipherSuite        uint16                // Ciphersuite negotiated for the session
@@ -288,6 +334,8 @@ type ClientSessionState struct {
 	serverCertificates []*x509.Certificate   // Certificate chain presented by the server
 	verifiedChains     [][]*x509.Certificate // Certificate chains we built for verification
 	receivedAt         time.Time             // When the session ticket was received from the server
+	ocspResponse       []byte                // Stapled OCSP response presented by the server
+	scts               [][]byte              // SCTs presented by the server
 
 	// TLS 1.3 fields.
 	nonce  []byte    // Ticket nonce sent by the server, to derive PSK
@@ -301,18 +349,8 @@ type ClientSessionState struct {
 // goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not
 // SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which
 // are supported via this interface.
-//go:generate sh -c "mockgen -package qtls -self_package github.com/Psiphon-Labs/qtls -destination mock_client_session_cache_test.go github.com/Psiphon-Labs/qtls ClientSessionCache"
-type ClientSessionCache interface {
-	// Get searches for a ClientSessionState associated with the given key.
-	// On return, ok is true if one was found.
-	Get(sessionKey string) (session *ClientSessionState, ok bool)
-
-	// Put adds the ClientSessionState to the cache with the given key. It might
-	// get called multiple times in a connection if a TLS 1.3 server provides
-	// more than one session ticket. If called with a nil *ClientSessionState,
-	// it should remove the cache entry.
-	Put(sessionKey string, cs *ClientSessionState)
-}
+//go:generate sh -c "mockgen -package qtls -destination mock_client_session_cache_test.go github.com/Psiphon-Labs/qtls-go1-15 ClientSessionCache"
+type ClientSessionCache = tls.ClientSessionCache
 
 // SignatureScheme is a tls.SignatureScheme
 type SignatureScheme = tls.SignatureScheme
@@ -343,7 +381,9 @@ const (
 
 // ClientHelloInfo contains information from a ClientHello message in order to
 // guide application logic in the GetCertificate and GetConfigForClient callbacks.
-type ClientHelloInfo struct {
+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
@@ -395,7 +435,9 @@ type ClientHelloInfo struct {
 // CertificateRequestInfo contains information from a server's
 // CertificateRequest message, which is used to demand a certificate and proof
 // of control from a client.
-type CertificateRequestInfo struct {
+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
@@ -424,26 +466,28 @@ type CertificateRequestInfo struct {
 // HTTPS.
 //
 // Renegotiation is not defined in TLS 1.3.
-type RenegotiationSupport int
+type RenegotiationSupport = tls.RenegotiationSupport
 
 const (
 	// RenegotiateNever disables renegotiation.
-	RenegotiateNever RenegotiationSupport = iota
+	RenegotiateNever = tls.RenegotiateNever
 
 	// RenegotiateOnceAsClient allows a remote server to request
 	// renegotiation once per connection.
-	RenegotiateOnceAsClient
+	RenegotiateOnceAsClient = tls.RenegotiateOnceAsClient
 
 	// RenegotiateFreelyAsClient allows a remote server to repeatedly
 	// request renegotiation.
-	RenegotiateFreelyAsClient
+	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 struct {
+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.
@@ -509,15 +553,10 @@ type Config struct {
 	// If GetConfigForClient is nil, the Config passed to Server() will be
 	// used for all connections.
 	//
-	// Uniquely for the fields in the returned Config, session ticket keys
-	// will be duplicated from the original Config if not set.
-	// Specifically, if SetSessionTicketKeys was called on the original
-	// config but not on the returned config then the ticket keys from the
-	// original config will be copied into the new config before use.
-	// Otherwise, if SessionTicketKey was set in the original config but
-	// not in the returned config then it will be copied into the returned
-	// config before use. If neither of those cases applies then the key
-	// material from the returned config will be used for session tickets.
+	// 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
@@ -533,6 +572,16 @@ type Config struct {
 	// be considered but the verifiedChains argument will always be nil.
 	VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
 
+	// VerifyConnection, if not nil, is called after normal certificate
+	// verification and after VerifyPeerCertificate by either a TLS client
+	// or server. If it returns a non-nil error, the handshake is aborted
+	// and that error results.
+	//
+	// If normal verification fails then the handshake will abort before
+	// considering this callback. This callback will run for all connections
+	// regardless of InsecureSkipVerify or ClientAuth settings.
+	VerifyConnection func(ConnectionState) error
+
 	// RootCAs defines the set of root certificate authorities
 	// that clients use when verifying server certificates.
 	// If RootCAs is nil, TLS uses the host's root CA set.
@@ -557,12 +606,12 @@ type Config struct {
 	// 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, TLS accepts any certificate
-	// presented by the server and any host name in that certificate.
-	// In this mode, TLS is susceptible to man-in-the-middle attacks.
-	// This should be used only for testing.
+	// 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 supported cipher suites for TLS versions up to
@@ -587,10 +636,10 @@ type Config struct {
 	// See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
 	// with random data before the first server handshake.
 	//
-	// If multiple servers are terminating connections for the same host
-	// they should all have the same SessionTicketKey. If the
-	// SessionTicketKey leaks, previously recorded and future TLS
-	// connections using that key might be compromised.
+	// 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
@@ -630,6 +679,29 @@ type Config struct {
 	// 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
+	// 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
+}
+
+// A RecordLayer handles encrypting and decrypting of TLS messages.
+type RecordLayer interface {
+	SetReadKey(encLevel EncryptionLevel, suite *CipherSuiteTLS13, trafficSecret []byte)
+	SetWriteKey(encLevel EncryptionLevel, suite *CipherSuiteTLS13, trafficSecret []byte)
+	ReadHandshakeMessage() ([]byte, error)
+	WriteRecord([]byte) (int, error)
+	SendAlert(uint8)
+}
+
+type ExtraConfig struct {
 	// GetExtensions, if not nil, is called before a message that allows
 	// sending of extensions is sent.
 	// Currently only implemented for the ClientHello message (for the client)
@@ -646,16 +718,6 @@ type Config struct {
 	// Only valid for TLS 1.3.
 	ReceivedExtensions func(handshakeMessageType uint8, exts []Extension)
 
-	serverInitOnce sync.Once // guards calling (*Config).serverInit
-
-	// mutex protects sessionTicketKeys.
-	mutex sync.RWMutex
-	// sessionTicketKeys contains zero or more ticket keys. If the length
-	// is zero, SessionTicketsDisabled must be true. The first key is used
-	// for new tickets and any subsequent keys can be used to decrypt old
-	// tickets.
-	sessionTicketKeys []ticketKey
-
 	// AlternativeRecordLayer is used by QUIC
 	AlternativeRecordLayer RecordLayer
 
@@ -702,18 +764,39 @@ type Config struct {
 	ClientHelloPRNG *prng.PRNG
 }
 
-// A RecordLayer handles encrypting and decrypting of TLS messages.
-type RecordLayer interface {
-	SetReadKey(encLevel EncryptionLevel, suite *CipherSuiteTLS13, trafficSecret []byte)
-	SetWriteKey(encLevel EncryptionLevel, suite *CipherSuiteTLS13, trafficSecret []byte)
-	ReadHandshakeMessage() ([]byte, error)
-	WriteRecord([]byte) (int, error)
-	SendAlert(uint8)
+// Clone clones.
+func (c *ExtraConfig) Clone() *ExtraConfig {
+	return &ExtraConfig{
+		GetExtensions:              c.GetExtensions,
+		ReceivedExtensions:         c.ReceivedExtensions,
+		AlternativeRecordLayer:     c.AlternativeRecordLayer,
+		EnforceNextProtoSelection:  c.EnforceNextProtoSelection,
+		MaxEarlyData:               c.MaxEarlyData,
+		Enable0RTT:                 c.Enable0RTT,
+		Accept0RTT:                 c.Accept0RTT,
+		Rejected0RTT:               c.Rejected0RTT,
+		GetAppDataForSessionState:  c.GetAppDataForSessionState,
+		SetAppDataFromSessionState: c.SetAppDataFromSessionState,
+	}
+}
+
+func (c *ExtraConfig) usesAlternativeRecordLayer() bool {
+	return c != nil && c.AlternativeRecordLayer != nil
 }
 
-// ticketKeyNameLen is the number of bytes of identifier that is prepended to
-// an encrypted session ticket in order to identify the key used to encrypt it.
-const ticketKeyNameLen = 16
+const (
+	// ticketKeyNameLen is the number of bytes of identifier that is prepended to
+	// an encrypted session ticket in order to identify the key used to encrypt it.
+	ticketKeyNameLen = 16
+
+	// ticketKeyLifetime is how long a ticket key remains valid and can be used to
+	// resume a client connection.
+	ticketKeyLifetime = 7 * 24 * time.Hour // 7 days
+
+	// ticketKeyRotation is how often the server should rotate the session ticket key
+	// that is used for new tickets.
+	ticketKeyRotation = 24 * time.Hour
+)
 
 // ticketKey is the internal representation of a session ticket key.
 type ticketKey struct {
@@ -722,16 +805,19 @@ type ticketKey struct {
 	keyName [ticketKeyNameLen]byte
 	aesKey  [16]byte
 	hmacKey [16]byte
+	// created is the time at which this ticket key was created. See Config.ticketKeys.
+	created time.Time
 }
 
 // ticketKeyFromBytes converts from the external representation of a session
 // ticket key to a ticketKey. Externally, session ticket keys are 32 random
 // bytes and this function expands that into sufficient name and key material.
-func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+func (c *config) ticketKeyFromBytes(b [32]byte) (key ticketKey) {
 	hashed := sha512.Sum512(b[:])
 	copy(key.keyName[:], hashed[:ticketKeyNameLen])
 	copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
 	copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
+	key.created = c.time()
 	return key
 }
 
@@ -739,19 +825,15 @@ func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
 // ticket, and the lifetime we set for tickets we send.
 const maxSessionTicketLifetime = 7 * 24 * time.Hour
 
-// Clone returns a shallow clone of c. It is safe to clone a Config that is
+// Clone returns a shallow clone of c or nil if c is nil. It is safe to clone a Config that is
 // being used concurrently by a TLS client or server.
-func (c *Config) Clone() *Config {
-	// Running serverInit ensures that it's safe to read
-	// SessionTicketsDisabled.
-	c.serverInitOnce.Do(func() { c.serverInit(nil) })
-
-	var sessionTicketKeys []ticketKey
+func (c *config) Clone() *config {
+	if c == nil {
+		return nil
+	}
 	c.mutex.RLock()
-	sessionTicketKeys = c.sessionTicketKeys
-	c.mutex.RUnlock()
-
-	return &Config{
+	defer c.mutex.RUnlock()
+	return &config{
 		Rand:                        c.Rand,
 		Time:                        c.Time,
 		Certificates:                c.Certificates,
@@ -760,6 +842,7 @@ func (c *Config) Clone() *Config {
 		GetClientCertificate:        c.GetClientCertificate,
 		GetConfigForClient:          c.GetConfigForClient,
 		VerifyPeerCertificate:       c.VerifyPeerCertificate,
+		VerifyConnection:            c.VerifyConnection,
 		RootCAs:                     c.RootCAs,
 		NextProtos:                  c.NextProtos,
 		ServerName:                  c.ServerName,
@@ -777,75 +860,130 @@ func (c *Config) Clone() *Config {
 		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
 		Renegotiation:               c.Renegotiation,
 		KeyLogWriter:                c.KeyLogWriter,
-		GetExtensions:               c.GetExtensions,
-		ReceivedExtensions:          c.ReceivedExtensions,
-		sessionTicketKeys:           sessionTicketKeys,
-		EnforceNextProtoSelection:   c.EnforceNextProtoSelection,
-		MaxEarlyData:                c.MaxEarlyData,
-		Enable0RTT:                  c.Enable0RTT,
-		Accept0RTT:                  c.Accept0RTT,
-		Rejected0RTT:                c.Rejected0RTT,
-		GetAppDataForSessionState:   c.GetAppDataForSessionState,
-		SetAppDataFromSessionState:  c.SetAppDataFromSessionState,
+		sessionTicketKeys:           c.sessionTicketKeys,
+		autoSessionTicketKeys:       c.autoSessionTicketKeys,
 	}
 }
 
-// serverInit is run under c.serverInitOnce to do initialization of c. If c was
-// returned by a GetConfigForClient callback then the argument should be the
-// Config that was passed to Server, otherwise it should be nil.
-func (c *Config) serverInit(originalConfig *Config) {
-	if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 {
+// 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
 	}
 
-	alreadySet := false
-	for _, b := range c.SessionTicketKey {
-		if b != 0 {
-			alreadySet = true
-			break
+	// 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)}
 	}
 
-	if !alreadySet {
-		if originalConfig != nil {
-			copy(c.SessionTicketKey[:], originalConfig.SessionTicketKey[:])
-		} else if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
-			c.SessionTicketsDisabled = true
-			return
+}
+
+// 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()
 	}
 
-	if originalConfig != nil {
-		originalConfig.mutex.RLock()
-		c.sessionTicketKeys = originalConfig.sessionTicketKeys
-		originalConfig.mutex.RUnlock()
-	} else {
-		c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+	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
 	}
-}
 
-func (c *Config) ticketKeys() []ticketKey {
-	c.mutex.RLock()
-	// c.sessionTicketKeys is constant once created. SetSessionTicketKeys
-	// will only update it by replacing it with a new value.
-	ret := c.sessionTicketKeys
+	// autoSessionTicketKeys are managed by auto-rotation.
 	c.mutex.RUnlock()
-	return ret
+	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.
-func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
+// 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] = ticketKeyFromBytes(bytes)
+		newKeys[i] = c.ticketKeyFromBytes(bytes)
 	}
 
 	c.mutex.Lock()
@@ -853,7 +991,7 @@ func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
 	c.mutex.Unlock()
 }
 
-func (c *Config) rand() io.Reader {
+func (c *config) rand() io.Reader {
 	r := c.Rand
 	if r == nil {
 		return rand.Reader
@@ -861,7 +999,7 @@ func (c *Config) rand() io.Reader {
 	return r
 }
 
-func (c *Config) time() time.Time {
+func (c *config) time() time.Time {
 	t := c.Time
 	if t == nil {
 		t = time.Now
@@ -869,7 +1007,7 @@ func (c *Config) time() time.Time {
 	return t()
 }
 
-func (c *Config) cipherSuites() []uint16 {
+func (c *config) cipherSuites() []uint16 {
 	s := c.CipherSuites
 	if s == nil {
 		s = defaultCipherSuites()
@@ -884,7 +1022,7 @@ var supportedVersions = []uint16{
 	VersionTLS10,
 }
 
-func (c *Config) supportedVersions() []uint16 {
+func (c *config) supportedVersions() []uint16 {
 	versions := make([]uint16, 0, len(supportedVersions))
 	for _, v := range supportedVersions {
 		if c != nil && c.MinVersion != 0 && v < c.MinVersion {
@@ -898,7 +1036,7 @@ func (c *Config) supportedVersions() []uint16 {
 	return versions
 }
 
-func (c *Config) maxSupportedVersion() uint16 {
+func (c *config) maxSupportedVersion() uint16 {
 	supportedVersions := c.supportedVersions()
 	if len(supportedVersions) == 0 {
 		return 0
@@ -922,14 +1060,14 @@ func supportedVersionsFromMax(maxVersion uint16) []uint16 {
 
 var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
 
-func (c *Config) curvePreferences() []CurveID {
+func (c *config) curvePreferences() []CurveID {
 	if c == nil || len(c.CurvePreferences) == 0 {
 		return defaultCurvePreferences
 	}
 	return c.CurvePreferences
 }
 
-func (c *Config) supportsCurve(curve CurveID) bool {
+func (c *config) supportsCurve(curve CurveID) bool {
 	for _, cc := range c.curvePreferences() {
 		if cc == curve {
 			return true
@@ -940,7 +1078,7 @@ func (c *Config) supportsCurve(curve CurveID) bool {
 
 // 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(peerVersions []uint16) (uint16, bool) {
+func (c *config) mutualVersion(peerVersions []uint16) (uint16, bool) {
 	supportedVersions := c.supportedVersions()
 	for _, peerVersion := range peerVersions {
 		for _, v := range supportedVersions {
@@ -956,7 +1094,7 @@ 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) {
+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)
@@ -1010,7 +1148,7 @@ func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, err
 //
 // 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 {
+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,
@@ -1020,7 +1158,8 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
 	if config == nil {
 		config = &Config{}
 	}
-	vers, ok := config.mutualVersion(chi.SupportedVersions)
+	conf := fromConfig(config)
+	vers, ok := conf.mutualVersion(chi.SupportedVersions)
 	if !ok {
 		return errors.New("no mutually supported protocol versions")
 	}
@@ -1028,7 +1167,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
 	// If the client specified the name they are trying to connect to, the
 	// certificate needs to be valid for it.
 	if chi.ServerName != "" {
-		x509Cert, err := c.leaf()
+		x509Cert, err := leafCertificate(c)
 		if err != nil {
 			return fmt.Errorf("failed to parse certificate: %w", err)
 		}
@@ -1058,7 +1197,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
 		}
 		// Finally, there needs to be a mutual cipher suite that uses the static
 		// RSA key exchange instead of ECDHE.
-		rsaCipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
+		rsaCipherSuite := selectCipherSuite(chi.CipherSuites, conf.cipherSuites(), func(c *cipherSuite) bool {
 			if c.flags&suiteECDHE != 0 {
 				return false
 			}
@@ -1089,7 +1228,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
 	}
 
 	// The only signed key exchange we support is ECDHE.
-	if !supportsECDHE(config, chi.SupportedCurves, chi.SupportedPoints) {
+	if !supportsECDHE(conf, chi.SupportedCurves, chi.SupportedPoints) {
 		return supportsRSAFallback(errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange"))
 	}
 
@@ -1110,7 +1249,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
 			}
 			var curveOk bool
 			for _, c := range chi.SupportedCurves {
-				if c == curve && config.supportsCurve(c) {
+				if c == curve && conf.supportsCurve(c) {
 					curveOk = true
 					break
 				}
@@ -1135,7 +1274,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
 	// Make sure that there is a mutually supported cipher suite that works with
 	// this certificate. Cipher suite selection will then apply the logic in
 	// reverse to pick it. See also serverHandshakeState.cipherSuiteOk.
-	cipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
+	cipherSuite := selectCipherSuite(chi.CipherSuites, conf.cipherSuites(), func(c *cipherSuite) bool {
 		if c.flags&suiteECDHE == 0 {
 			return false
 		}
@@ -1160,38 +1299,6 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
 	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.
@@ -1199,15 +1306,17 @@ func (cri *CertificateRequestInfo) SupportsCertificate(c *Certificate) error {
 // 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() {
+func (c *config) BuildNameToCertificate() {
 	c.NameToCertificate = make(map[string]*Certificate)
 	for i := range c.Certificates {
 		cert := &c.Certificates[i]
-		x509Cert, err := cert.leaf()
+		x509Cert, err := leafCertificate(cert)
 		if err != nil {
 			continue
 		}
-		if len(x509Cert.Subject.CommonName) > 0 {
+		// If SANs are *not* present, some clients will consider the certificate
+		// valid for the name in the Common Name.
+		if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 {
 			c.NameToCertificate[x509Cert.Subject.CommonName] = cert
 		}
 		for _, san := range x509Cert.DNSNames {
@@ -1225,7 +1334,7 @@ const (
 	keyLogLabelServerTraffic   = "SERVER_TRAFFIC_SECRET_0"
 )
 
-func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
+func (c *config) writeKeyLog(label string, clientRandom, secret []byte) error {
 	if c.KeyLogWriter == nil {
 		return nil
 	}
@@ -1244,31 +1353,11 @@ func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
 var writerMutex sync.Mutex
 
 // A Certificate is a chain of one or more certificates, leaf first.
-type Certificate struct {
-	Certificate [][]byte
-	// PrivateKey contains the private key corresponding to the public key in
-	// Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey.
-	// For a server up to TLS 1.2, it can also implement crypto.Decrypter with
-	// an RSA PublicKey.
-	PrivateKey crypto.PrivateKey
-	// SupportedSignatureAlgorithms is an optional list restricting what
-	// signature algorithms the PrivateKey can be used for.
-	SupportedSignatureAlgorithms []SignatureScheme
-	// OCSPStaple contains an optional OCSP response which will be served
-	// to clients that request it.
-	OCSPStaple []byte
-	// SignedCertificateTimestamps contains an optional list of Signed
-	// Certificate Timestamps which will be served to clients that request it.
-	SignedCertificateTimestamps [][]byte
-	// Leaf is the parsed form of the leaf certificate, which may be initialized
-	// using x509.ParseCertificate to reduce per-handshake processing. If nil,
-	// the leaf certificate will be parsed as needed.
-	Leaf *x509.Certificate
-}
+type Certificate = tls.Certificate
 
 // leaf returns the parsed leaf certificate, either from c.Leaf or by parsing
 // the corresponding c.Certificate[0].
-func (c *Certificate) leaf() (*x509.Certificate, error) {
+func leafCertificate(c *Certificate) (*x509.Certificate, error) {
 	if c.Leaf != nil {
 		return c.Leaf, nil
 	}
@@ -1357,13 +1446,6 @@ func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
 	return nil, false
 }
 
-// TODO(jsing): Make these available to both crypto/x509 and crypto/tls.
-type dsaSignature struct {
-	R, S *big.Int
-}
-
-type ecdsaSignature dsaSignature
-
 var emptyConfig Config
 
 func defaultConfig() *Config {
@@ -1386,23 +1468,21 @@ func defaultCipherSuitesTLS13() []uint16 {
 	return varDefaultCipherSuitesTLS13
 }
 
+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
+)
+
 func initDefaultCipherSuites() {
 	var topCipherSuites []uint16
 
-	// Check the cpu flags for each platform that has optimized GCM implementations.
-	// Worst case, these variables will just all be false.
-	var (
-		hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
-		hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
-		// Keep in sync with crypto/aes/cipher_s390x.go.
-		// TODO: check for s390
-		// hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
-		hasGCMAsmS390X = false
-
-		hasGCMAsm = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X
-	)
-
-	if hasGCMAsm {
+	if hasAESGCMHardwareSupport {
 		// If AES-GCM hardware is provided then prioritise AES-GCM
 		// cipher suites.
 		topCipherSuites = []uint16{
@@ -1465,3 +1545,51 @@ func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlg
 	}
 	return false
 }
+
+var aesgcmCiphers = map[uint16]bool{
+	// 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,
+	// 1.3
+	TLS_AES_128_GCM_SHA256: true,
+	TLS_AES_256_GCM_SHA384: true,
+}
+
+var nonAESGCMAEADCiphers = map[uint16]bool{
+	// 1.2
+	TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:   true,
+	TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: true,
+	// 1.3
+	TLS_CHACHA20_POLY1305_SHA256: true,
+}
+
+// aesgcmPreferred returns whether the first valid 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 {
+		c := cipherSuiteByID(cID)
+		if c == nil {
+			c13 := cipherSuiteTLS13ByID(cID)
+			if c13 == nil {
+				continue
+			}
+			return aesgcmCiphers[cID]
+		}
+		return aesgcmCiphers[cID]
+	}
+	return false
+}
+
+// deprioritizeAES reorders cipher preference lists by rearranging
+// adjacent AEAD ciphers such that AES-GCM based ciphers are moved
+// after other AEAD ciphers. It returns a fresh slice.
+func deprioritizeAES(ciphers []uint16) []uint16 {
+	reordered := make([]uint16, len(ciphers))
+	copy(reordered, ciphers)
+	sort.SliceStable(reordered, func(i, j int) bool {
+		return nonAESGCMAEADCiphers[reordered[i]] && aesgcmCiphers[reordered[j]]
+	})
+	return reordered
+}

+ 146 - 88
vendor/github.com/Psiphon-Labs/qtls/conn.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/conn.go

@@ -13,6 +13,7 @@ import (
 	"crypto/x509"
 	"errors"
 	"fmt"
+	"hash"
 	"io"
 	"net"
 	"sync"
@@ -24,8 +25,9 @@ import (
 // It implements the net.Conn interface.
 type Conn struct {
 	// constant
-	conn     net.Conn
-	isClient bool
+	conn        net.Conn
+	isClient    bool
+	handshakeFn func() error // (*Conn).clientHandshake or serverHandshake
 
 	// handshakeStatus is 1 if the connection is currently transferring
 	// application data (i.e. is not currently processing a handshake).
@@ -36,10 +38,12 @@ type Conn struct {
 	handshakeErr   error   // error resulting from handshake
 	vers           uint16  // TLS version
 	haveVers       bool    // version has been negotiated
-	config         *Config // configuration passed to constructor
+	config         *config // configuration passed to constructor
 	// handshakes counts the number of handshakes performed on the
 	// connection so far. If renegotiation is disabled then this is either
 	// zero or one.
+	extraConfig *ExtraConfig
+
 	handshakes       int
 	didResume        bool // whether this connection was a session resumption
 	cipherSuite      uint16
@@ -66,6 +70,11 @@ type Conn struct {
 	// layer is set. nil if config.SessionTicketsDisabled.
 	resumptionSecret []byte
 
+	// ticketKeys is the set of active session ticket keys for this
+	// connection. The first one is used to encrypt new tickets and
+	// all are tried to decrypt tickets.
+	ticketKeys []ticketKey
+
 	// clientFinishedIsFirst is true if the client sent the first Finished
 	// message during the most recent handshake. This is recorded because
 	// the first transmitted Finished message is the tls-unique
@@ -85,15 +94,14 @@ type Conn struct {
 	clientFinished [12]byte
 	serverFinished [12]byte
 
-	clientProtocol         string
-	clientProtocolFallback bool
+	// clientProtocol is the negotiated ALPN protocol.
+	clientProtocol string
 
 	// input/output
 	in, out   halfConn
 	rawInput  bytes.Buffer // raw input, starting with a record header
 	input     bytes.Reader // application data waiting to be read, from rawInput.Next
 	hand      bytes.Buffer // handshake data waiting to be read
-	outBuf    []byte       // scratch buffer used by out.encrypt
 	buffering bool         // whether records are buffered in sendBuf
 	sendBuf   []byte       // a buffer of records waiting to be sent
 
@@ -156,29 +164,43 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
 type halfConn struct {
 	sync.Mutex
 
-	err            error       // first permanent error
-	version        uint16      // protocol version
-	cipher         interface{} // cipher algorithm
-	mac            macFunction
-	seq            [8]byte  // 64-bit sequence number
-	additionalData [13]byte // to avoid allocs; interface method args escape
+	err     error       // first permanent error
+	version uint16      // protocol version
+	cipher  interface{} // cipher algorithm
+	mac     hash.Hash
+	seq     [8]byte // 64-bit sequence number
+
+	scratchBuf [13]byte // to avoid allocs; interface method args escape
 
 	nextCipher interface{} // next encryption state
-	nextMac    macFunction // next MAC algorithm
+	nextMac    hash.Hash   // next MAC algorithm
 
 	trafficSecret []byte // current TLS 1.3 traffic secret
 
 	setKeyCallback func(encLevel EncryptionLevel, suite *CipherSuiteTLS13, trafficSecret []byte)
 }
 
+type 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 {
-	hc.err = err
-	return err
+	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 interface{}, mac macFunction) {
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac hash.Hash) {
 	hc.version = version
 	hc.nextCipher = cipher
 	hc.nextMac = mac
@@ -352,15 +374,14 @@ func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
 			}
 			payload = payload[explicitNonceLen:]
 
-			additionalData := hc.additionalData[:]
+			var additionalData []byte
 			if hc.version == VersionTLS13 {
 				additionalData = record[:recordHeaderLen]
 			} else {
-				copy(additionalData, hc.seq[:])
-				copy(additionalData[8:], record[:3])
+				additionalData = append(hc.scratchBuf[:0], hc.seq[:]...)
+				additionalData = append(additionalData, record[:3]...)
 				n := len(payload) - c.Overhead()
-				additionalData[11] = byte(n >> 8)
-				additionalData[12] = byte(n)
+				additionalData = append(additionalData, byte(n>>8), byte(n))
 			}
 
 			var err error
@@ -426,7 +447,7 @@ func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
 		record[3] = byte(n >> 8)
 		record[4] = byte(n)
 		remoteMAC := payload[n : n+macSize]
-		localMAC := hc.mac.MAC(hc.seq[0:], record[:recordHeaderLen], payload[:n], payload[n+macSize:])
+		localMAC := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload[:n], payload[n+macSize:])
 
 		// This is equivalent to checking the MACs and paddingGood
 		// separately, but in constant-time to prevent distinguishing
@@ -448,9 +469,9 @@ func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
 }
 
 func (c *Conn) setAlternativeRecordLayer() {
-	if c.config.AlternativeRecordLayer != nil {
-		c.in.setKeyCallback = c.config.AlternativeRecordLayer.SetReadKey
-		c.out.setKeyCallback = c.config.AlternativeRecordLayer.SetWriteKey
+	if c.extraConfig != nil && c.extraConfig.AlternativeRecordLayer != nil {
+		c.in.setKeyCallback = c.extraConfig.AlternativeRecordLayer.SetReadKey
+		c.out.setKeyCallback = c.extraConfig.AlternativeRecordLayer.SetWriteKey
 	}
 }
 
@@ -469,7 +490,7 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) {
 }
 
 // encrypt encrypts payload, adding the appropriate nonce and/or MAC, and
-// appends it to record, which contains the record header.
+// appends it to record, which must already contain the record header.
 func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, error) {
 	if hc.cipher == nil {
 		return append(record, payload...), nil
@@ -486,7 +507,7 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
 			// an 8 bytes nonce but its nonces must be unpredictable (see RFC
 			// 5246, Appendix F.3), forcing us to use randomness. That's not
 			// 3DES' biggest problem anyway because the birthday bound on block
-			// collision is reached first due to its simlarly small block size
+			// collision is reached first due to its similarly small block size
 			// (see the Sweet32 attack).
 			copy(explicitNonce, hc.seq[:])
 		} else {
@@ -496,14 +517,10 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
 		}
 	}
 
-	var mac []byte
-	if hc.mac != nil {
-		mac = hc.mac.MAC(hc.seq[:], record[:recordHeaderLen], payload, nil)
-	}
-
 	var dst []byte
 	switch c := hc.cipher.(type) {
 	case cipher.Stream:
+		mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
 		record, dst = sliceForAppend(record, len(payload)+len(mac))
 		c.XORKeyStream(dst[:len(payload)], payload)
 		c.XORKeyStream(dst[len(payload):], mac)
@@ -527,11 +544,12 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
 			record = c.Seal(record[:recordHeaderLen],
 				nonce, record[recordHeaderLen:], record[:recordHeaderLen])
 		} else {
-			copy(hc.additionalData[:], hc.seq[:])
-			copy(hc.additionalData[8:], record)
-			record = c.Seal(record, nonce, payload, hc.additionalData[:])
+			additionalData := append(hc.scratchBuf[:0], hc.seq[:]...)
+			additionalData = append(additionalData, record[:recordHeaderLen]...)
+			record = c.Seal(record, nonce, payload, additionalData)
 		}
 	case cbcMode:
+		mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
 		blockSize := c.BlockSize()
 		plaintextLen := len(payload) + len(mac)
 		paddingLen := blockSize - plaintextLen%blockSize
@@ -832,8 +850,8 @@ func (c *Conn) sendAlertLocked(err alert) error {
 
 // sendAlert sends a TLS alert message.
 func (c *Conn) sendAlert(err alert) error {
-	if c.config.AlternativeRecordLayer != nil {
-		c.config.AlternativeRecordLayer.SendAlert(uint8(err))
+	if c.extraConfig != nil && c.extraConfig.AlternativeRecordLayer != nil {
+		c.extraConfig.AlternativeRecordLayer.SendAlert(uint8(err))
 		return &net.OpError{Op: "local error", Err: err}
 	}
 
@@ -942,9 +960,28 @@ func (c *Conn) flush() (int, error) {
 	return n, err
 }
 
+// outBufPool pools the record-sized scratch buffers used by writeRecordLocked.
+var outBufPool = sync.Pool{
+	New: func() interface{} {
+		return new([]byte)
+	},
+}
+
 // writeRecordLocked writes a TLS record with the given type and payload to the
 // connection and updates the record layer state.
 func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
+	outBufPtr := outBufPool.Get().(*[]byte)
+	outBuf := *outBufPtr
+	defer func() {
+		// You might be tempted to simplify this by just passing &outBuf to Put,
+		// but that would make the local copy of the outBuf slice header escape
+		// to the heap, causing an allocation. Instead, we keep around the
+		// pointer to the slice header returned by Get, which is already on the
+		// heap, and overwrite and return that.
+		*outBufPtr = outBuf
+		outBufPool.Put(outBufPtr)
+	}()
+
 	var n int
 	for len(data) > 0 {
 		m := len(data)
@@ -952,8 +989,8 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
 			m = maxPayload
 		}
 
-		_, c.outBuf = sliceForAppend(c.outBuf[:0], recordHeaderLen)
-		c.outBuf[0] = byte(typ)
+		_, outBuf = sliceForAppend(outBuf[:0], recordHeaderLen)
+		outBuf[0] = byte(typ)
 		vers := c.vers
 		if vers == 0 {
 			// Some TLS servers fail if the record version is
@@ -964,17 +1001,17 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
 			// See RFC 8446, Section 5.1.
 			vers = VersionTLS12
 		}
-		c.outBuf[1] = byte(vers >> 8)
-		c.outBuf[2] = byte(vers)
-		c.outBuf[3] = byte(m >> 8)
-		c.outBuf[4] = byte(m)
+		outBuf[1] = byte(vers >> 8)
+		outBuf[2] = byte(vers)
+		outBuf[3] = byte(m >> 8)
+		outBuf[4] = byte(m)
 
 		var err error
-		c.outBuf, err = c.out.encrypt(c.outBuf, data[:m], c.config.rand())
+		outBuf, err = c.out.encrypt(outBuf, data[:m], c.config.rand())
 		if err != nil {
 			return n, err
 		}
-		if _, err := c.write(c.outBuf); err != nil {
+		if _, err := c.write(outBuf); err != nil {
 			return n, err
 		}
 		n += m
@@ -993,11 +1030,11 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
 // writeRecord writes a TLS record with the given type and payload to the
 // connection and updates the record layer state.
 func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
-	if c.config.AlternativeRecordLayer != nil {
+	if c.extraConfig != nil && c.extraConfig.AlternativeRecordLayer != nil {
 		if typ == recordTypeChangeCipherSpec {
 			return len(data), nil
 		}
-		return c.config.AlternativeRecordLayer.WriteRecord(data)
+		return c.extraConfig.AlternativeRecordLayer.WriteRecord(data)
 	}
 
 	c.out.Lock()
@@ -1010,9 +1047,9 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
 // the record layer.
 func (c *Conn) readHandshake() (interface{}, error) {
 	var data []byte
-	if c.config.AlternativeRecordLayer != nil {
+	if c.extraConfig != nil && c.extraConfig.AlternativeRecordLayer != nil {
 		var err error
-		data, err = c.config.AlternativeRecordLayer.ReadHandshakeMessage()
+		data, err = c.extraConfig.AlternativeRecordLayer.ReadHandshakeMessage()
 		if err != nil {
 			return nil, err
 		}
@@ -1100,17 +1137,21 @@ func (c *Conn) readHandshake() (interface{}, error) {
 }
 
 var (
-	errClosed   = errors.New("tls: use of closed connection")
 	errShutdown = errors.New("tls: protocol is shutdown")
 )
 
 // Write writes data to the connection.
+//
+// As Write calls Handshake, in order to prevent indefinite blocking a deadline
+// must be set for both Read and Write before Write is called when the handshake
+// has not yet completed. See SetDeadline, SetReadDeadline, and
+// SetWriteDeadline.
 func (c *Conn) Write(b []byte) (int, error) {
 	// interlock with Close below
 	for {
 		x := atomic.LoadInt32(&c.activeCall)
 		if x&1 != 0 {
-			return 0, errClosed
+			return 0, net.ErrClosed
 		}
 		if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
 			break
@@ -1267,8 +1308,12 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
 	return nil
 }
 
-// Read can be made to time out and return a net.Error with Timeout() == true
-// after a fixed time limit; see SetDeadline and SetReadDeadline.
+// Read reads data from the connection.
+//
+// As Read calls Handshake, in order to prevent indefinite blocking a deadline
+// must be set for both Read and Write before Read is called when the handshake
+// has not yet completed. See SetDeadline, SetReadDeadline, and
+// SetWriteDeadline.
 func (c *Conn) Read(b []byte) (int, error) {
 	if err := c.Handshake(); err != nil {
 		return 0, err
@@ -1319,7 +1364,7 @@ func (c *Conn) Close() error {
 	for {
 		x = atomic.LoadInt32(&c.activeCall)
 		if x&1 != 0 {
-			return errClosed
+			return net.ErrClosed
 		}
 		if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) {
 			break
@@ -1336,9 +1381,10 @@ func (c *Conn) Close() error {
 	}
 
 	var alertErr error
-
 	if c.handshakeComplete() {
-		alertErr = c.closeNotify()
+		if err := c.closeNotify(); err != nil {
+			alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err)
+		}
 	}
 
 	if err := c.conn.Close(); err != nil {
@@ -1365,16 +1411,24 @@ func (c *Conn) closeNotify() error {
 	defer c.out.Unlock()
 
 	if !c.closeNotifySent {
+		// Set a Write Deadline to prevent possibly blocking forever.
+		c.SetWriteDeadline(time.Now().Add(time.Second * 5))
 		c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
 		c.closeNotifySent = true
+		// Any subsequent writes will fail.
+		c.SetWriteDeadline(time.Now())
 	}
 	return c.closeNotifyErr
 }
 
 // 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.
+//
+// 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
+// the Dialer's DialContext method.
 func (c *Conn) Handshake() error {
 	c.handshakeMutex.Lock()
 	defer c.handshakeMutex.Unlock()
@@ -1389,11 +1443,7 @@ func (c *Conn) Handshake() error {
 	c.in.Lock()
 	defer c.in.Unlock()
 
-	if c.isClient {
-		c.handshakeErr = c.clientHandshake()
-	} else {
-		c.handshakeErr = c.serverHandshake()
-	}
+	c.handshakeErr = c.handshakeFn()
 	if c.handshakeErr == nil {
 		c.handshakes++
 	} else {
@@ -1413,37 +1463,45 @@ func (c *Conn) Handshake() error {
 func (c *Conn) ConnectionState() ConnectionState {
 	c.handshakeMutex.Lock()
 	defer c.handshakeMutex.Unlock()
+	return c.connectionStateLocked()
+}
+
+// ConnectionStateWith0RTT returns basic TLS details (incl. 0-RTT status) about the connection.
+func (c *Conn) ConnectionStateWith0RTT() ConnectionStateWith0RTT {
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+	return ConnectionStateWith0RTT{
+		ConnectionState: c.connectionStateLocked(),
+		Used0RTT:        c.used0RTT,
+	}
+}
 
-	var state ConnectionState
+func (c *Conn) connectionStateLocked() ConnectionState {
+	var state connectionState
 	state.HandshakeComplete = c.handshakeComplete()
+	state.Version = c.vers
+	state.NegotiatedProtocol = c.clientProtocol
+	state.DidResume = c.didResume
+	state.NegotiatedProtocolIsMutual = true
 	state.ServerName = c.serverName
-
-	if state.HandshakeComplete {
-		state.Version = c.vers
-		state.NegotiatedProtocol = c.clientProtocol
-		state.DidResume = c.didResume
-		state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
-		state.CipherSuite = c.cipherSuite
-		state.PeerCertificates = c.peerCertificates
-		state.VerifiedChains = c.verifiedChains
-		state.SignedCertificateTimestamps = c.scts
-		state.OCSPResponse = c.ocspResponse
-		if !c.didResume && c.vers != VersionTLS13 {
-			if c.clientFinishedIsFirst {
-				state.TLSUnique = c.clientFinished[:]
-			} else {
-				state.TLSUnique = c.serverFinished[:]
-			}
-		}
-		state.Used0RTT = c.used0RTT
-		if c.config.Renegotiation != RenegotiateNever {
-			state.ekm = noExportedKeyingMaterial
+	state.CipherSuite = c.cipherSuite
+	state.PeerCertificates = c.peerCertificates
+	state.VerifiedChains = c.verifiedChains
+	state.SignedCertificateTimestamps = c.scts
+	state.OCSPResponse = c.ocspResponse
+	if !c.didResume && c.vers != VersionTLS13 {
+		if c.clientFinishedIsFirst {
+			state.TLSUnique = c.clientFinished[:]
 		} else {
-			state.ekm = c.ekm
+			state.TLSUnique = c.serverFinished[:]
 		}
 	}
-
-	return state
+	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

+ 3 - 4
vendor/github.com/Psiphon-Labs/qtls/go.mod → vendor/github.com/Psiphon-Labs/qtls-go1-16/go.mod

@@ -1,10 +1,9 @@
-module github.com/Psiphon-Labs/qtls
+module github.com/Psiphon-Labs/qtls-go1-16
 
-go 1.14
+go 1.16
 
 require (
-	github.com/golang/mock v1.4.0
+	github.com/golang/mock v1.4.4
 	golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d
 	golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
 )
-

+ 2 - 5
vendor/github.com/Psiphon-Labs/qtls/go.sum → vendor/github.com/Psiphon-Labs/qtls-go1-16/go.sum

@@ -1,5 +1,5 @@
-github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
 golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -10,8 +10,5 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
 golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

+ 146 - 91
vendor/github.com/Psiphon-Labs/qtls/handshake_client.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_client.go

@@ -14,6 +14,7 @@ import (
 	"crypto/x509"
 	"errors"
 	"fmt"
+	"hash"
 	"io"
 	"net"
 	"strings"
@@ -32,7 +33,7 @@ type clientHandshakeState struct {
 	suite        *cipherSuite
 	finishedHash finishedHash
 	masterSecret []byte
-	session      *ClientSessionState
+	session      *clientSessionState
 }
 
 func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
@@ -53,12 +54,23 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
 		return nil, nil, errors.New("tls: NextProtos values too large")
 	}
 
-	supportedVersions := config.supportedVersions()
-	if len(supportedVersions) == 0 {
-		return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
+	var supportedVersions []uint16
+	var clientHelloVersion uint16
+	if c.extraConfig.usesAlternativeRecordLayer() {
+		if config.maxSupportedVersion() < VersionTLS13 {
+			return nil, nil, errors.New("tls: MaxVersion prevents QUIC from using TLS 1.3")
+		}
+		// Only offer TLS 1.3 when QUIC is used.
+		supportedVersions = []uint16{VersionTLS13}
+		clientHelloVersion = VersionTLS13
+	} else {
+		supportedVersions = config.supportedVersions()
+		if len(supportedVersions) == 0 {
+			return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
+		}
+		clientHelloVersion = config.maxSupportedVersion()
 	}
 
-	clientHelloVersion := supportedVersions[0]
 	// 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.
@@ -78,9 +90,11 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
 		secureRenegotiationSupported: true,
 		alpnProtocols:                config.NextProtos,
 		supportedVersions:            supportedVersions,
+	}
 
-		// [Psiphon]
-		PRNG: config.ClientHelloPRNG,
+	// [Psiphon]
+	if c.extraConfig != nil {
+		hello.PRNG = c.extraConfig.ClientHelloPRNG
 	}
 
 	if c.handshakes > 0 {
@@ -116,7 +130,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
 	// A random session ID is used to detect when the server accepted a ticket
 	// and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as
 	// a compatibility measure (see RFC 8446, Section 4.1.2).
-	if c.config.AlternativeRecordLayer == nil {
+	if c.extraConfig == nil || c.extraConfig.AlternativeRecordLayer == 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())
@@ -154,8 +168,8 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
 		hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
 	}
 
-	if hello.supportedVersions[0] == VersionTLS13 && config.GetExtensions != nil {
-		hello.additionalExtensions = config.GetExtensions(typeClientHello)
+	if hello.supportedVersions[0] == VersionTLS13 && c.extraConfig != nil && c.extraConfig.GetExtensions != nil {
+		hello.additionalExtensions = c.extraConfig.GetExtensions(typeClientHello)
 	}
 
 	return hello, params, nil
@@ -163,7 +177,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, ecdheParameters, error) {
 
 func (c *Conn) clientHandshake() (err error) {
 	if c.config == nil {
-		c.config = defaultConfig()
+		c.config = fromConfig(defaultConfig())
 	}
 	c.setAlternativeRecordLayer()
 
@@ -175,11 +189,12 @@ func (c *Conn) clientHandshake() (err error) {
 	if err != nil {
 		return err
 	}
+	c.serverName = hello.serverName
 
 	cacheKey, session, earlySecret, binderKey := c.loadSession(hello)
 	if cacheKey != "" && session != nil {
 		var deletedTicket bool
-		if session.vers == VersionTLS13 && hello.earlyData && c.config.Enable0RTT {
+		if session.vers == VersionTLS13 && hello.earlyData && c.extraConfig != nil && c.extraConfig.Enable0RTT {
 			// don't reuse a session ticket that enabled 0-RTT
 			c.config.ClientSessionCache.Put(cacheKey, nil)
 			deletedTicket = true
@@ -229,6 +244,18 @@ func (c *Conn) clientHandshake() (err error) {
 		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()
+	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,
@@ -258,7 +285,7 @@ func (c *Conn) clientHandshake() (err error) {
 	// If we had a successful handshake and hs.session is different from
 	// the one already cached - cache a new one.
 	if cacheKey != "" && hs.session != nil && session != hs.session {
-		c.config.ClientSessionCache.Put(cacheKey, hs.session)
+		c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(hs.session))
 	}
 
 	return nil
@@ -266,7 +293,7 @@ func (c *Conn) clientHandshake() (err error) {
 
 // extract the app data saved in the session.nonce,
 // and set the session.nonce to the actual nonce value
-func (c *Conn) decodeSessionState(session *ClientSessionState) (uint32 /* max early data */, []byte /* app data */, bool /* ok */) {
+func (c *Conn) decodeSessionState(session *clientSessionState) (uint32 /* max early data */, []byte /* app data */, bool /* ok */) {
 	s := cryptobyte.String(session.nonce)
 	var version uint16
 	if !s.ReadUint16(&version) {
@@ -292,7 +319,7 @@ func (c *Conn) decodeSessionState(session *ClientSessionState) (uint32 /* max ea
 }
 
 func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
-	session *ClientSessionState, earlySecret, binderKey []byte) {
+	session *clientSessionState, earlySecret, binderKey []byte) {
 	if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
 		return "", nil, nil, nil
 	}
@@ -314,10 +341,12 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
 
 	// Try to resume a previously negotiated TLS session, if available.
 	cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
-	session, ok := c.config.ClientSessionCache.Get(cacheKey)
-	if !ok || session == nil {
+	sess, ok := c.config.ClientSessionCache.Get(cacheKey)
+	if !ok || sess == nil {
 		return cacheKey, nil, nil, nil
 	}
+	session = fromClientSessionState(sess)
+
 	var appData []byte
 	var maxEarlyData uint32
 	if session.vers == VersionTLS13 {
@@ -409,14 +438,16 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
 		session.nonce, cipherSuite.hash.Size())
 	earlySecret = cipherSuite.extract(psk, nil)
 	binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
-	hello.earlyData = c.config.Enable0RTT && maxEarlyData > 0
+	if c.extraConfig != nil {
+		hello.earlyData = c.extraConfig.Enable0RTT && maxEarlyData > 0
+	}
 	transcript := cipherSuite.hash.New()
 	transcript.Write(hello.marshalWithoutBinders())
 	pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)}
 	hello.updateBinders(pskBinders)
 
-	if session.vers == VersionTLS13 && c.config.SetAppDataFromSessionState != nil {
-		c.config.SetAppDataFromSessionState(appData)
+	if session.vers == VersionTLS13 && c.extraConfig != nil && c.extraConfig.SetAppDataFromSessionState != nil {
+		c.extraConfig.SetAppDataFromSessionState(appData)
 	}
 	return
 }
@@ -465,6 +496,7 @@ func (hs *clientHandshakeState) handshake() error {
 	hs.finishedHash.Write(hs.serverHello.marshal())
 
 	c.buffering = true
+	c.didResume = isResume
 	if isResume {
 		if err := hs.establishKeys(); err != nil {
 			return err
@@ -476,6 +508,15 @@ func (hs *clientHandshakeState) handshake() error {
 			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
 		}
@@ -505,7 +546,6 @@ func (hs *clientHandshakeState) handshake() error {
 	}
 
 	c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
-	c.didResume = isResume
 	atomic.StoreUint32(&c.handshakeStatus, 1)
 
 	return nil
@@ -535,25 +575,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 	}
 	hs.finishedHash.Write(certMsg.marshal())
 
-	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")
-		}
-	}
-
 	msg, err = c.readHandshake()
 	if err != nil {
 		return err
@@ -582,6 +603,25 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 		}
 	}
 
+	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)
@@ -714,12 +754,12 @@ func (hs *clientHandshakeState) establishKeys() error {
 	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
 		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
 	var clientCipher, serverCipher interface{}
-	var clientHash, serverHash macFunction
+	var clientHash, serverHash hash.Hash
 	if hs.suite.cipher != nil {
 		clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
-		clientHash = hs.suite.mac(c.vers, clientMAC)
+		clientHash = hs.suite.mac(clientMAC)
 		serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
-		serverHash = hs.suite.mac(c.vers, serverMAC)
+		serverHash = hs.suite.mac(serverMAC)
 	} else {
 		clientCipher = hs.suite.aead(clientKey, clientIV)
 		serverCipher = hs.suite.aead(serverKey, serverIV)
@@ -767,18 +807,18 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
 		}
 	}
 
-	clientDidALPN := len(hs.hello.alpnProtocols) > 0
-	serverHasALPN := len(hs.serverHello.alpnProtocol) > 0
-
-	if !clientDidALPN && serverHasALPN {
-		c.sendAlert(alertHandshakeFailure)
-		return false, errors.New("tls: server advertised unrequested ALPN extension")
-	}
-
-	if serverHasALPN {
+	if hs.serverHello.alpnProtocol != "" {
+		if len(hs.hello.alpnProtocols) == 0 {
+			c.sendAlert(alertUnsupportedExtension)
+			return false, errors.New("tls: server advertised unrequested ALPN extension")
+		}
+		if mutualProtocol([]string{hs.serverHello.alpnProtocol}, hs.hello.alpnProtocols) == "" {
+			c.sendAlert(alertUnsupportedExtension)
+			return false, errors.New("tls: server selected unadvertised ALPN protocol")
+		}
 		c.clientProtocol = hs.serverHello.alpnProtocol
-		c.clientProtocolFallback = false
 	}
+
 	c.scts = hs.serverHello.scts
 
 	if !hs.serverResumedSession() {
@@ -795,10 +835,17 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
 		return false, errors.New("tls: server resumed a session with a different cipher suite")
 	}
 
-	// Restore masterSecret and peerCerts from previous state
+	// Restore masterSecret, peerCerts, and ocspResponse from previous state
 	hs.masterSecret = hs.session.masterSecret
 	c.peerCertificates = hs.session.serverCertificates
 	c.verifiedChains = hs.session.verifiedChains
+	c.ocspResponse = hs.session.ocspResponse
+	// Let the ServerHello SCTs override the session SCTs from the original
+	// connection, if any are provided
+	if len(c.scts) == 0 && len(hs.session.scts) != 0 {
+		c.scts = hs.session.scts
+	}
+
 	return true, nil
 }
 
@@ -847,7 +894,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
 	}
 	hs.finishedHash.Write(sessionTicketMsg.marshal())
 
-	hs.session = &ClientSessionState{
+	hs.session = &clientSessionState{
 		sessionTicket:      sessionTicketMsg.ticket,
 		vers:               c.vers,
 		cipherSuite:        hs.suite.id,
@@ -855,6 +902,8 @@ func (hs *clientHandshakeState) readSessionTicket() error {
 		serverCertificates: c.peerCertificates,
 		verifiedChains:     c.verifiedChains,
 		receivedAt:         c.config.time(),
+		ocspResponse:       c.ocspResponse,
+		scts:               c.scts,
 	}
 
 	return nil
@@ -908,13 +957,6 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
 		}
 	}
 
-	if c.config.VerifyPeerCertificate != nil {
-		if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
-			c.sendAlert(alertBadCertificate)
-			return err
-		}
-	}
-
 	switch certs[0].PublicKey.(type) {
 	case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
 		break
@@ -925,21 +967,27 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
 
 	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
 }
 
-// tls11SignatureSchemes contains the signature schemes that we synthesise for
-// a TLS <= 1.1 connection, based on the supported certificate types.
-var (
-	tls11SignatureSchemes      = []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1}
-	tls11SignatureSchemesECDSA = tls11SignatureSchemes[:3]
-	tls11SignatureSchemesRSA   = tls11SignatureSchemes[3:]
-)
-
 // certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
 // <= 1.2 CertificateRequest, making an effort to fill in missing information.
 func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
-	cri := &CertificateRequestInfo{
+	cri := &certificateRequestInfo{
 		AcceptableCAs: certReq.certificateAuthorities,
 		Version:       vers,
 	}
@@ -955,19 +1003,27 @@ func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg)
 	}
 
 	if !certReq.hasSignatureAlgorithm {
-		// Prior to TLS 1.2, the signature schemes were not
-		// included in the certificate request message. In this
-		// case we use a plausible list based on the acceptable
-		// certificate types.
+		// 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 = tls11SignatureSchemes
+			cri.SignatureSchemes = []SignatureScheme{
+				ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
+				PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
+			}
 		case rsaAvail:
-			cri.SignatureSchemes = tls11SignatureSchemesRSA
+			cri.SignatureSchemes = []SignatureScheme{
+				PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
+			}
 		case ecAvail:
-			cri.SignatureSchemes = tls11SignatureSchemesECDSA
+			cri.SignatureSchemes = []SignatureScheme{
+				ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
+			}
 		}
-		return cri
+		return toCertificateRequestInfo(cri)
 	}
 
 	// Filter the signature schemes based on the certificate types.
@@ -990,7 +1046,7 @@ func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg)
 		}
 	}
 
-	return cri
+	return toCertificateRequestInfo(cri)
 }
 
 func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate, error) {
@@ -1009,29 +1065,28 @@ func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate,
 	return new(Certificate), nil
 }
 
+const clientSessionCacheKeyPrefix = "qtls-"
+
 // clientSessionCacheKey returns a key used to cache sessionTickets that could
 // be used to resume previously negotiated TLS sessions with a server.
-func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
+func clientSessionCacheKey(serverAddr net.Addr, config *config) string {
 	if len(config.ServerName) > 0 {
-		return config.ServerName
+		return clientSessionCacheKeyPrefix + config.ServerName
 	}
-	return serverAddr.String()
+	return clientSessionCacheKeyPrefix + serverAddr.String()
 }
 
-// mutualProtocol finds the mutual Next Protocol Negotiation or ALPN protocol
-// given list of possible protocols and a list of the preference order. The
-// first list must not be empty. It returns the resulting protocol and flag
-// indicating if the fallback case was reached.
-func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
+// mutualProtocol finds the mutual ALPN protocol given list of possible
+// protocols and a list of the preference order.
+func mutualProtocol(protos, preferenceProtos []string) string {
 	for _, s := range preferenceProtos {
 		for _, c := range protos {
 			if s == c {
-				return s, false
+				return s
 			}
 		}
 	}
-
-	return protos[0], true
+	return ""
 }
 
 // hostnameInSNI converts name into an appropriate hostname for SNI.

+ 85 - 56
vendor/github.com/Psiphon-Labs/qtls/handshake_client_tls13.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_client_tls13.go

@@ -25,7 +25,7 @@ type clientHandshakeStateTLS13 struct {
 	hello       *clientHelloMsg
 	ecdheParams ecdheParameters
 
-	session     *ClientSessionState
+	session     *clientSessionState
 	earlySecret []byte
 	binderKey   []byte
 
@@ -180,51 +180,62 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
 	c := hs.c
 
 	// The first ClientHello gets double-hashed into the transcript upon a
-	// HelloRetryRequest. See RFC 8446, Section 4.4.1.
+	// HelloRetryRequest. (The idea is that the server might offload transcript
+	// storage to the client in the cookie.) See RFC 8446, Section 4.4.1.
 	chHash := hs.transcript.Sum(nil)
 	hs.transcript.Reset()
 	hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
 	hs.transcript.Write(chHash)
 	hs.transcript.Write(hs.serverHello.marshal())
 
+	// 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")
 	}
 
-	curveID := hs.serverHello.selectedGroup
-	if curveID == 0 {
-		c.sendAlert(alertMissingExtension)
-		return errors.New("tls: received HelloRetryRequest without selected group")
-	}
-	curveOK := false
-	for _, id := range hs.hello.supportedCurves {
-		if id == curveID {
-			curveOK = true
-			break
+	// If the server sent a key_share extension selecting a group, ensure it's
+	// a group we advertised but did not send a key share for, and send a key
+	// share for it this time.
+	if curveID := hs.serverHello.selectedGroup; curveID != 0 {
+		curveOK := false
+		for _, id := range hs.hello.supportedCurves {
+			if id == curveID {
+				curveOK = true
+				break
+			}
 		}
+		if !curveOK {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: server selected unsupported group")
+		}
+		if hs.ecdheParams.CurveID() == curveID {
+			c.sendAlert(alertIllegalParameter)
+			return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
+		}
+		if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
+			c.sendAlert(alertInternalError)
+			return errors.New("tls: CurvePreferences includes unsupported curve")
+		}
+		params, err := generateECDHEParameters(c.config.rand(), curveID)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
+		}
+		hs.ecdheParams = params
+		hs.hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
 	}
-	if !curveOK {
-		c.sendAlert(alertIllegalParameter)
-		return errors.New("tls: server selected unsupported group")
-	}
-	if hs.ecdheParams.CurveID() == curveID {
-		c.sendAlert(alertIllegalParameter)
-		return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
-	}
-	if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
-		c.sendAlert(alertInternalError)
-		return errors.New("tls: CurvePreferences includes unsupported curve")
-	}
-	params, err := generateECDHEParameters(c.config.rand(), curveID)
-	if err != nil {
-		c.sendAlert(alertInternalError)
-		return err
-	}
-	hs.ecdheParams = params
-	hs.hello.keyShares = []keyShare{{group: curveID, data: params.PublicKey()}}
-
-	hs.hello.cookie = hs.serverHello.cookie
 
 	hs.hello.raw = nil
 	if len(hs.hello.pskIdentities) > 0 {
@@ -251,10 +262,10 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
 		}
 	}
 
-	hs.hello.earlyData = false // disable 0-RTT
-	if c.config.Rejected0RTT != nil {
-		c.config.Rejected0RTT()
+	if hs.hello.earlyData && c.extraConfig != nil && c.extraConfig.Rejected0RTT != nil {
+		c.extraConfig.Rejected0RTT()
 	}
+	hs.hello.earlyData = false // disable 0-RTT
 
 	hs.transcript.Write(hs.hello.marshal())
 	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
@@ -332,6 +343,8 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error {
 	c.didResume = true
 	c.peerCertificates = hs.session.serverCertificates
 	c.verifiedChains = hs.session.verifiedChains
+	c.ocspResponse = hs.session.ocspResponse
+	c.scts = hs.session.scts
 	return nil
 }
 
@@ -390,34 +403,39 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error {
 		c.sendAlert(alertUnexpectedMessage)
 		return unexpectedMessageError(encryptedExtensions, msg)
 	}
-	if hs.c.config.ReceivedExtensions != nil {
-		hs.c.config.ReceivedExtensions(typeEncryptedExtensions, encryptedExtensions.additionalExtensions)
+	// Notify the caller if 0-RTT was rejected.
+	if !encryptedExtensions.earlyData && hs.hello.earlyData && c.extraConfig != nil && c.extraConfig.Rejected0RTT != nil {
+		c.extraConfig.Rejected0RTT()
+	}
+	c.used0RTT = encryptedExtensions.earlyData
+	if hs.c.extraConfig != nil && hs.c.extraConfig.ReceivedExtensions != nil {
+		hs.c.extraConfig.ReceivedExtensions(typeEncryptedExtensions, encryptedExtensions.additionalExtensions)
 	}
 	hs.transcript.Write(encryptedExtensions.marshal())
 
-	if len(encryptedExtensions.alpnProtocol) != 0 && len(hs.hello.alpnProtocols) == 0 {
-		c.sendAlert(alertUnsupportedExtension)
-		return errors.New("tls: server advertised unrequested ALPN extension")
-	}
-	if c.config.EnforceNextProtoSelection {
+	if c.extraConfig != nil && c.extraConfig.EnforceNextProtoSelection {
 		if len(encryptedExtensions.alpnProtocol) == 0 {
 			// the server didn't select an ALPN
 			c.sendAlert(alertNoApplicationProtocol)
 			return errors.New("ALPN negotiation failed. Server didn't offer any protocols")
 		}
-		if _, fallback := mutualProtocol([]string{encryptedExtensions.alpnProtocol}, hs.c.config.NextProtos); fallback {
+		if mutualProtocol([]string{encryptedExtensions.alpnProtocol}, hs.c.config.NextProtos) == "" {
 			// the protocol selected by the server was not offered
 			c.sendAlert(alertNoApplicationProtocol)
 			return fmt.Errorf("ALPN negotiation failed. Server offered: %q", encryptedExtensions.alpnProtocol)
 		}
 	}
-	c.clientProtocol = encryptedExtensions.alpnProtocol
-	// Notify the caller if 0-RTT was rejected.
-	if !encryptedExtensions.earlyData && hs.hello.earlyData && c.config.Rejected0RTT != nil {
-		c.config.Rejected0RTT()
+	if encryptedExtensions.alpnProtocol != "" {
+		if len(hs.hello.alpnProtocols) == 0 {
+			c.sendAlert(alertUnsupportedExtension)
+			return errors.New("tls: server advertised unrequested ALPN extension")
+		}
+		if mutualProtocol([]string{encryptedExtensions.alpnProtocol}, hs.hello.alpnProtocols) == "" {
+			c.sendAlert(alertUnsupportedExtension)
+			return errors.New("tls: server selected unadvertised ALPN protocol")
+		}
+		c.clientProtocol = encryptedExtensions.alpnProtocol
 	}
-	c.used0RTT = encryptedExtensions.earlyData
-
 	return nil
 }
 
@@ -427,6 +445,15 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
 	// 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
 	}
 
@@ -555,11 +582,11 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
 		return nil
 	}
 
-	cert, err := c.getClientCertificate(&CertificateRequestInfo{
+	cert, err := c.getClientCertificate(toCertificateRequestInfo(&certificateRequestInfo{
 		AcceptableCAs:    hs.certReq.certificateAuthorities,
 		SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
 		Version:          c.vers,
-	})
+	}))
 	if err != nil {
 		return err
 	}
@@ -674,8 +701,8 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
 	copy(nonceWithEarlyData[4:], msg.nonce)
 
 	var appData []byte
-	if c.config.GetAppDataForSessionState != nil {
-		appData = c.config.GetAppDataForSessionState()
+	if c.extraConfig != nil && c.extraConfig.GetAppDataForSessionState != nil {
+		appData = c.extraConfig.GetAppDataForSessionState()
 	}
 	var b cryptobyte.Builder
 	b.AddUint16(clientSessionStateVersion) // revision
@@ -691,7 +718,7 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
 	// to do the least amount of work on NewSessionTicket messages before we
 	// know if the ticket will be used. Forward secrecy of resumed connections
 	// is guaranteed by the requirement for pskModeDHE.
-	session := &ClientSessionState{
+	session := &clientSessionState{
 		sessionTicket:      msg.label,
 		vers:               c.vers,
 		cipherSuite:        c.cipherSuite,
@@ -702,10 +729,12 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
 		nonce:              b.BytesOrPanic(),
 		useBy:              c.config.time().Add(lifetime),
 		ageAdd:             msg.ageAdd,
+		ocspResponse:       c.ocspResponse,
+		scts:               c.scts,
 	}
 
 	cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
-	c.config.ClientSessionCache.Put(cacheKey, session)
+	c.config.ClientSessionCache.Put(cacheKey, toClientSessionState(session))
 
 	return nil
 }

+ 3 - 4
vendor/github.com/Psiphon-Labs/qtls/handshake_messages.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_messages.go

@@ -100,6 +100,9 @@ type clientHelloMsg struct {
 }
 
 func (m *clientHelloMsg) marshal() []byte {
+	if m.raw != nil {
+		return m.raw
+	}
 
 	// [Psiphon]
 	// Randomize the Client Hello.
@@ -107,10 +110,6 @@ func (m *clientHelloMsg) marshal() []byte {
 		return m.marshalRandomized()
 	}
 
-	if m.raw != nil {
-		return m.raw
-	}
-
 	var b cryptobyte.Builder
 	b.AddUint8(typeClientHello)
 	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {

+ 109 - 42
vendor/github.com/Psiphon-Labs/qtls/handshake_server.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_server.go

@@ -13,8 +13,10 @@ import (
 	"crypto/x509"
 	"errors"
 	"fmt"
+	"hash"
 	"io"
 	"sync/atomic"
+	"time"
 )
 
 // serverHandshakeState contains details of a server handshake in progress.
@@ -36,9 +38,6 @@ type serverHandshakeState struct {
 
 // serverHandshake performs a TLS handshake as a server.
 func (c *Conn) serverHandshake() error {
-	// If this is the first server handshake, we generate a random key to
-	// encrypt the tickets with.
-	c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) })
 	c.setAlternativeRecordLayer()
 
 	clientHello, err := c.readClientHello()
@@ -52,6 +51,12 @@ func (c *Conn) serverHandshake() error {
 			clientHello: clientHello,
 		}
 		return hs.handshake()
+	} else if c.extraConfig.usesAlternativeRecordLayer() {
+		// This should already have been caught by the check that the ClientHello doesn't
+		// offer any (supported) versions older than TLS 1.3.
+		// Check again to make sure we can't be tricked into using an older version.
+		c.sendAlert(alertProtocolVersion)
+		return errors.New("tls: negotiated TLS < 1.3 when using QUIC")
 	}
 
 	hs := serverHandshakeState{
@@ -72,19 +77,15 @@ func (hs *serverHandshakeState) handshake() error {
 	c.buffering = true
 	if hs.checkForResumption() {
 		// The client has included a session ticket and so we do an abbreviated handshake.
+		c.didResume = true
 		if err := hs.doResumeHandshake(); err != nil {
 			return err
 		}
 		if err := hs.establishKeys(); err != nil {
 			return err
 		}
-		// ticketSupported is set in a resumption handshake if the
-		// ticket from the client was encrypted with an old session
-		// ticket key and thus a refreshed ticket should be sent.
-		if hs.hello.ticketSupported {
-			if err := hs.sendSessionTicket(); err != nil {
-				return err
-			}
+		if err := hs.sendSessionTicket(); err != nil {
+			return err
 		}
 		if err := hs.sendFinished(c.serverFinished[:]); err != nil {
 			return err
@@ -96,7 +97,6 @@ func (hs *serverHandshakeState) handshake() error {
 		if err := hs.readFinished(nil); err != nil {
 			return err
 		}
-		c.didResume = true
 	} else {
 		// The client didn't include a session ticket, or it wasn't
 		// valid so we do a full handshake.
@@ -143,21 +143,45 @@ func (c *Conn) readClientHello() (*clientHelloMsg, error) {
 		return nil, unexpectedMessageError(clientHello, msg)
 	}
 
+	var configForClient *config
+	originalConfig := c.config
 	if c.config.GetConfigForClient != nil {
-		chi := clientHelloInfo(c, clientHello)
-		if newConfig, err := c.config.GetConfigForClient(chi); err != nil {
+		chi := newClientHelloInfo(c, clientHello)
+		if cfc, err := c.config.GetConfigForClient(chi); err != nil {
 			c.sendAlert(alertInternalError)
 			return nil, err
-		} else if newConfig != nil {
-			newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
-			c.config = newConfig
+		} else if cfc != nil {
+			configForClient = fromConfig(cfc)
+			c.config = configForClient
 		}
 	}
+	c.ticketKeys = originalConfig.ticketKeys(configForClient)
 
 	clientVersions := clientHello.supportedVersions
 	if len(clientHello.supportedVersions) == 0 {
 		clientVersions = supportedVersionsFromMax(clientHello.vers)
 	}
+	if c.extraConfig.usesAlternativeRecordLayer() {
+		// In QUIC, the client MUST NOT offer any old TLS versions.
+		// Here, we can only check that none of the other supported versions of this library
+		// (TLS 1.0 - TLS 1.2) is offered. We don't check for any SSL versions here.
+		for _, ver := range clientVersions {
+			if ver == VersionTLS13 {
+				continue
+			}
+			for _, v := range supportedVersions {
+				if ver == v {
+					c.sendAlert(alertProtocolVersion)
+					return nil, fmt.Errorf("tls: client offered old TLS version %#x", ver)
+				}
+			}
+		}
+		// Make the config we're using allows us to use TLS 1.3.
+		if c.config.maxSupportedVersion() < VersionTLS13 {
+			c.sendAlert(alertInternalError)
+			return nil, errors.New("tls: MaxVersion prevents QUIC from using TLS 1.3")
+		}
+	}
 	c.vers, ok = c.config.mutualVersion(clientVersions)
 	if !ok {
 		c.sendAlert(alertProtocolVersion)
@@ -194,7 +218,7 @@ func (hs *serverHandshakeState) processClientHello() error {
 	serverRandom := hs.hello.random
 	// Downgrade protection canaries. See RFC 8446, Section 4.1.3.
 	maxVers := c.config.maxSupportedVersion()
-	if maxVers >= VersionTLS12 && c.vers < maxVers {
+	if maxVers >= VersionTLS12 && c.vers < maxVers || testingOnlyForceDowngradeCanary {
 		if c.vers == VersionTLS12 {
 			copy(serverRandom[24:], downgradeCanaryTLS12)
 		} else {
@@ -220,13 +244,13 @@ func (hs *serverHandshakeState) processClientHello() error {
 	}
 
 	if len(hs.clientHello.alpnProtocols) > 0 {
-		if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
+		if selectedProto := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); selectedProto != "" {
 			hs.hello.alpnProtocol = selectedProto
 			c.clientProtocol = selectedProto
 		}
 	}
 
-	hs.cert, err = c.config.getCertificate(clientHelloInfo(c, hs.clientHello))
+	hs.cert, err = c.config.getCertificate(newClientHelloInfo(c, hs.clientHello))
 	if err != nil {
 		if err == errNoCertificates {
 			c.sendAlert(alertUnrecognizedName)
@@ -278,7 +302,7 @@ func (hs *serverHandshakeState) processClientHello() error {
 
 // 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 {
+func supportsECDHE(c *config, supportedCurves []CurveID, supportedPoints []uint8) bool {
 	supportsCurve := false
 	for _, curve := range supportedCurves {
 		if c.supportsCurve(curve) {
@@ -305,9 +329,23 @@ func (hs *serverHandshakeState) pickCipherSuite() error {
 	if c.config.PreferServerCipherSuites {
 		preferenceList = c.config.cipherSuites()
 		supportedList = hs.clientHello.cipherSuites
+
+		// If the client does not seem to have hardware support for AES-GCM,
+		// and the application did not specify a cipher suite preference order,
+		// prefer other AEAD ciphers even if we prioritized AES-GCM ciphers
+		// by default.
+		if c.config.CipherSuites == nil && !aesgcmPreferred(hs.clientHello.cipherSuites) {
+			preferenceList = deprioritizeAES(preferenceList)
+		}
 	} else {
 		preferenceList = hs.clientHello.cipherSuites
 		supportedList = c.config.cipherSuites()
+
+		// If we don't have hardware support for AES-GCM, prefer other AEAD
+		// ciphers even if the client prioritized AES-GCM.
+		if !hasAESGCMHardwareSupport {
+			preferenceList = deprioritizeAES(preferenceList)
+		}
 	}
 
 	hs.suite = selectCipherSuite(preferenceList, supportedList, hs.cipherSuiteOk)
@@ -315,6 +353,7 @@ func (hs *serverHandshakeState) pickCipherSuite() error {
 		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 {
@@ -369,6 +408,11 @@ func (hs *serverHandshakeState) checkForResumption() bool {
 		return false
 	}
 
+	createdAt := time.Unix(int64(hs.sessionState.createdAt), 0)
+	if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+		return false
+	}
+
 	// Never resume a session for a different TLS version.
 	if c.vers != hs.sessionState.vers {
 		return false
@@ -409,6 +453,7 @@ 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
@@ -427,6 +472,13 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
 		return err
 	}
 
+	if c.config.VerifyConnection != nil {
+		if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+			c.sendAlert(alertBadCertificate)
+			return err
+		}
+	}
+
 	hs.masterSecret = hs.sessionState.masterSecret
 
 	return nil
@@ -551,6 +603,12 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 			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)
@@ -628,13 +686,13 @@ func (hs *serverHandshakeState) establishKeys() error {
 		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
 
 	var clientCipher, serverCipher interface{}
-	var clientHash, serverHash macFunction
+	var clientHash, serverHash hash.Hash
 
 	if hs.suite.aead == nil {
 		clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
-		clientHash = hs.suite.mac(c.vers, clientMAC)
+		clientHash = hs.suite.mac(clientMAC)
 		serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
-		serverHash = hs.suite.mac(c.vers, serverMAC)
+		serverHash = hs.suite.mac(serverMAC)
 	} else {
 		clientCipher = hs.suite.aead(clientKey, clientIV)
 		serverCipher = hs.suite.aead(serverKey, serverIV)
@@ -676,6 +734,9 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
 }
 
 func (hs *serverHandshakeState) sendSessionTicket() error {
+	// ticketSupported is set in a resumption handshake if the
+	// ticket from the client was encrypted with an old session
+	// ticket key and thus a refreshed ticket should be sent.
 	if !hs.hello.ticketSupported {
 		return nil
 	}
@@ -683,6 +744,13 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
 	c := hs.c
 	m := new(newSessionTicketMsg)
 
+	createdAt := uint64(c.config.time().Unix())
+	if hs.sessionState != nil {
+		// If this is re-wrapping an old key, then keep
+		// the original time it was created.
+		createdAt = hs.sessionState.createdAt
+	}
+
 	var certsFromClient [][]byte
 	for _, cert := range c.peerCertificates {
 		certsFromClient = append(certsFromClient, cert.Raw)
@@ -690,6 +758,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
 	state := sessionState{
 		vers:         c.vers,
 		cipherSuite:  hs.suite.id,
+		createdAt:    createdAt,
 		masterSecret: hs.masterSecret,
 		certificates: certsFromClient,
 	}
@@ -721,7 +790,6 @@ func (hs *serverHandshakeState) sendFinished(out []byte) error {
 		return err
 	}
 
-	c.cipherSuite = hs.suite.id
 	copy(out, finished.verifyData)
 
 	return nil
@@ -767,6 +835,19 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
 		c.verifiedChains = chains
 	}
 
+	c.peerCertificates = certs
+	c.ocspResponse = certificate.OCSPStaple
+	c.scts = certificate.SignedCertificateTimestamps
+
+	if len(certs) > 0 {
+		switch certs[0].PublicKey.(type) {
+		case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
+		default:
+			c.sendAlert(alertUnsupportedCertificate)
+			return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+		}
+	}
+
 	if c.config.VerifyPeerCertificate != nil {
 		if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
 			c.sendAlert(alertBadCertificate)
@@ -774,30 +855,16 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
 		}
 	}
 
-	if len(certs) == 0 {
-		return nil
-	}
-
-	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)
-	}
-
-	c.peerCertificates = certs
-	c.ocspResponse = certificate.OCSPStaple
-	c.scts = certificate.SignedCertificateTimestamps
 	return nil
 }
 
-func clientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
+func newClientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
 	supportedVersions := clientHello.supportedVersions
 	if len(clientHello.supportedVersions) == 0 {
 		supportedVersions = supportedVersionsFromMax(clientHello.vers)
 	}
 
-	return &ClientHelloInfo{
+	return toClientHelloInfo(&clientHelloInfo{
 		CipherSuites:      clientHello.cipherSuites,
 		ServerName:        clientHello.serverName,
 		SupportedCurves:   clientHello.supportedCurves,
@@ -806,6 +873,6 @@ func clientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
 		SupportedProtos:   clientHello.alpnProtocols,
 		SupportedVersions: supportedVersions,
 		Conn:              c.conn,
-		config:            c.config,
-	}
+		config:            toConfig(c.config),
+	})
 }

+ 45 - 12
vendor/github.com/Psiphon-Labs/qtls/handshake_server_tls13.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/handshake_server_tls13.go

@@ -140,22 +140,39 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error {
 	hs.hello.compressionMethod = compressionNone
 
 	var preferenceList, supportedList, ourList []uint16
+	var useConfiguredCipherSuites bool
 	for _, suiteID := range c.config.CipherSuites {
 		for _, suite := range cipherSuitesTLS13 {
 			if suite.id == suiteID {
 				ourList = append(ourList, suiteID)
+				break
 			}
 		}
 	}
-	if len(ourList) == 0 {
+	if len(ourList) > 0 {
+		useConfiguredCipherSuites = true
+	} else {
 		ourList = defaultCipherSuitesTLS13()
 	}
 	if c.config.PreferServerCipherSuites {
 		preferenceList = ourList
 		supportedList = hs.clientHello.cipherSuites
+
+		// If the client does not seem to have hardware support for AES-GCM,
+		// prefer other AEAD ciphers even if we prioritized AES-GCM ciphers
+		// by default.
+		if !useConfiguredCipherSuites && !aesgcmPreferred(hs.clientHello.cipherSuites) {
+			preferenceList = deprioritizeAES(preferenceList)
+		}
 	} else {
 		preferenceList = hs.clientHello.cipherSuites
 		supportedList = ourList
+
+		// If we don't have hardware support for AES-GCM, prefer other AEAD
+		// ciphers even if the client prioritized AES-GCM.
+		if !hasAESGCMHardwareSupport {
+			preferenceList = deprioritizeAES(preferenceList)
+		}
 	}
 	for _, suiteID := range preferenceList {
 		hs.suite = mutualCipherSuiteTLS13(supportedList, suiteID)
@@ -223,12 +240,12 @@ GroupSelection:
 
 	c.serverName = hs.clientHello.serverName
 
-	if c.config.ReceivedExtensions != nil {
-		c.config.ReceivedExtensions(typeClientHello, hs.clientHello.additionalExtensions)
+	if c.extraConfig != nil && c.extraConfig.ReceivedExtensions != nil {
+		c.extraConfig.ReceivedExtensions(typeClientHello, hs.clientHello.additionalExtensions)
 	}
 
 	if len(hs.clientHello.alpnProtocols) > 0 {
-		if selectedProto, fallback := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); !fallback {
+		if selectedProto := mutualProtocol(hs.clientHello.alpnProtocols, c.config.NextProtos); selectedProto != "" {
 			hs.encryptedExtensions.alpnProtocol = selectedProto
 			c.clientProtocol = selectedProto
 		}
@@ -284,7 +301,8 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
 			}
 
 			if sessionState.alpn == c.clientProtocol &&
-				c.config.Accept0RTT != nil && c.config.Accept0RTT(sessionState.appData) {
+				c.extraConfig != nil && c.extraConfig.MaxEarlyData > 0 &&
+				c.extraConfig.Accept0RTT != nil && c.extraConfig.Accept0RTT(sessionState.appData) {
 				hs.encryptedExtensions.earlyData = true
 				c.used0RTT = true
 			}
@@ -333,13 +351,14 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
 			return errors.New("tls: invalid PSK binder")
 		}
 
+		c.didResume = true
 		if err := c.processCertsFromClient(sessionState.certificate); err != nil {
 			return err
 		}
 
 		h := cloneHash(hs.transcript, hs.suite.hash)
 		h.Write(hs.clientHello.marshal())
-		if sessionState.maxEarlyData > 0 && c.config.MaxEarlyData > 0 {
+		if hs.encryptedExtensions.earlyData {
 			clientEarlySecret := hs.suite.deriveSecret(hs.earlySecret, "c e traffic", h)
 			c.in.exportKey(Encryption0RTT, hs.suite, clientEarlySecret)
 			if err := c.config.writeKeyLog(keyLogLabelEarlyTraffic, hs.clientHello.random, clientEarlySecret); err != nil {
@@ -351,7 +370,6 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
 		hs.hello.selectedIdentityPresent = true
 		hs.hello.selectedIdentity = uint16(i)
 		hs.usingPSK = true
-		c.didResume = true
 		return nil
 	}
 
@@ -399,7 +417,7 @@ func (hs *serverHandshakeStateTLS13) pickCertificate() error {
 		return c.sendAlert(alertMissingExtension)
 	}
 
-	certificate, err := c.config.getCertificate(clientHelloInfo(c, hs.clientHello))
+	certificate, err := c.config.getCertificate(newClientHelloInfo(c, hs.clientHello))
 	if err != nil {
 		if err == errNoCertificates {
 			c.sendAlert(alertUnrecognizedName)
@@ -558,7 +576,7 @@ func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool {
 func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
 	c := hs.c
 
-	if c.config.EnforceNextProtoSelection && len(c.clientProtocol) == 0 {
+	if c.extraConfig != nil && c.extraConfig.EnforceNextProtoSelection && len(c.clientProtocol) == 0 {
 		c.sendAlert(alertNoApplicationProtocol)
 		return fmt.Errorf("ALPN negotiation failed. Client offered: %q", hs.clientHello.alpnProtocols)
 	}
@@ -600,8 +618,8 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
 		return err
 	}
 
-	if hs.c.config.GetExtensions != nil {
-		hs.encryptedExtensions.additionalExtensions = hs.c.config.GetExtensions(typeEncryptedExtensions)
+	if hs.c.extraConfig != nil && hs.c.extraConfig.GetExtensions != nil {
+		hs.encryptedExtensions.additionalExtensions = hs.c.extraConfig.GetExtensions(typeEncryptedExtensions)
 	}
 
 	hs.transcript.Write(hs.encryptedExtensions.marshal())
@@ -768,7 +786,7 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
 	// Don't send session tickets when the alternative record layer is set.
 	// Instead, save the resumption secret on the Conn.
 	// Session tickets can then be generated by calling Conn.GetSessionTicket().
-	if hs.c.config.AlternativeRecordLayer != nil {
+	if hs.c.extraConfig != nil && hs.c.extraConfig.AlternativeRecordLayer != nil {
 		return nil
 	}
 
@@ -787,6 +805,14 @@ 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
 	}
 
@@ -809,6 +835,13 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
 		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 {
 		msg, err = c.readHandshake()
 		if err != nil {

+ 9 - 9
vendor/github.com/Psiphon-Labs/qtls/key_agreement.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/key_agreement.go

@@ -22,11 +22,11 @@ var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
 // 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) {
+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) {
+func (ka rsaKeyAgreement) processClientKeyExchange(config *config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
 	if len(ckx.ciphertext) < 2 {
 		return nil, errClientKeyExchange
 	}
@@ -40,7 +40,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
 	if !ok {
 		return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
 	}
-	// Perform constant time RSA PKCS#1 v1.5 decryption
+	// 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
@@ -54,11 +54,11 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
 	return preMasterSecret, nil
 }
 
-func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+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) {
+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)
@@ -142,7 +142,7 @@ type ecdheKeyAgreement struct {
 	preMasterSecret []byte
 }
 
-func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+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) {
@@ -231,7 +231,7 @@ func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Cer
 	return skx, nil
 }
 
-func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+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
 	}
@@ -244,7 +244,7 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert
 	return preMasterSecret, nil
 }
 
-func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+func (ka *ecdheKeyAgreement) processServerKeyExchange(config *config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
 	if len(skx.key) < 4 {
 		return errServerKeyExchange
 	}
@@ -325,7 +325,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
 	return nil
 }
 
-func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+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")
 	}

+ 2 - 5
vendor/github.com/Psiphon-Labs/qtls/key_schedule.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/key_schedule.go

@@ -188,11 +188,8 @@ func (p *nistParameters) SharedKey(peerPublicKey []byte) []byte {
 	}
 
 	xShared, _ := curve.ScalarMult(x, y, p.privateKey)
-	sharedKey := make([]byte, (curve.Params().BitSize+7)>>3)
-	xBytes := xShared.Bytes()
-	copy(sharedKey[len(sharedKey)-len(xBytes):], xBytes)
-
-	return sharedKey
+	sharedKey := make([]byte, (curve.Params().BitSize+7)/8)
+	return xShared.FillBytes(sharedKey)
 }
 
 type x25519Parameters struct {

+ 0 - 0
vendor/github.com/Psiphon-Labs/qtls/prf.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/prf.go


+ 52 - 78
vendor/github.com/Psiphon-Labs/qtls/ticket.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/ticket.go

@@ -23,88 +23,56 @@ import (
 type sessionState struct {
 	vers         uint16
 	cipherSuite  uint16
-	masterSecret []byte
-	certificates [][]byte
+	createdAt    uint64
+	masterSecret []byte // opaque master_secret<1..2^16-1>;
+	// struct { opaque certificate<1..2^24-1> } Certificate;
+	certificates [][]byte // Certificate certificate_list<0..2^24-1>;
+
 	// usedOldKey is true if the ticket from which this session came from
 	// was encrypted with an older key and thus should be refreshed.
 	usedOldKey bool
 }
 
-func (s *sessionState) marshal() []byte {
-	length := 2 + 2 + 2 + len(s.masterSecret) + 2
-	for _, cert := range s.certificates {
-		length += 4 + len(cert)
-	}
-
-	ret := make([]byte, length)
-	x := ret
-	x[0] = byte(s.vers >> 8)
-	x[1] = byte(s.vers)
-	x[2] = byte(s.cipherSuite >> 8)
-	x[3] = byte(s.cipherSuite)
-	x[4] = byte(len(s.masterSecret) >> 8)
-	x[5] = byte(len(s.masterSecret))
-	x = x[6:]
-	copy(x, s.masterSecret)
-	x = x[len(s.masterSecret):]
-
-	x[0] = byte(len(s.certificates) >> 8)
-	x[1] = byte(len(s.certificates))
-	x = x[2:]
-
-	for _, cert := range s.certificates {
-		x[0] = byte(len(cert) >> 24)
-		x[1] = byte(len(cert) >> 16)
-		x[2] = byte(len(cert) >> 8)
-		x[3] = byte(len(cert))
-		copy(x[4:], cert)
-		x = x[4+len(cert):]
-	}
-
-	return ret
+func (m *sessionState) marshal() []byte {
+	var b cryptobyte.Builder
+	b.AddUint16(m.vers)
+	b.AddUint16(m.cipherSuite)
+	addUint64(&b, m.createdAt)
+	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+		b.AddBytes(m.masterSecret)
+	})
+	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+		for _, cert := range m.certificates {
+			b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+				b.AddBytes(cert)
+			})
+		}
+	})
+	return b.BytesOrPanic()
 }
 
-func (s *sessionState) unmarshal(data []byte) bool {
-	if len(data) < 8 {
-		return false
-	}
-
-	s.vers = uint16(data[0])<<8 | uint16(data[1])
-	s.cipherSuite = uint16(data[2])<<8 | uint16(data[3])
-	masterSecretLen := int(data[4])<<8 | int(data[5])
-	data = data[6:]
-	if len(data) < masterSecretLen {
+func (m *sessionState) unmarshal(data []byte) bool {
+	*m = sessionState{usedOldKey: m.usedOldKey}
+	s := cryptobyte.String(data)
+	if ok := s.ReadUint16(&m.vers) &&
+		s.ReadUint16(&m.cipherSuite) &&
+		readUint64(&s, &m.createdAt) &&
+		readUint16LengthPrefixed(&s, &m.masterSecret) &&
+		len(m.masterSecret) != 0; !ok {
 		return false
 	}
-
-	s.masterSecret = data[:masterSecretLen]
-	data = data[masterSecretLen:]
-
-	if len(data) < 2 {
+	var certList cryptobyte.String
+	if !s.ReadUint24LengthPrefixed(&certList) {
 		return false
 	}
-
-	numCerts := int(data[0])<<8 | int(data[1])
-	data = data[2:]
-
-	s.certificates = make([][]byte, numCerts)
-	for i := range s.certificates {
-		if len(data) < 4 {
-			return false
-		}
-		certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3])
-		data = data[4:]
-		if certLen < 0 {
-			return false
-		}
-		if len(data) < certLen {
+	for !certList.Empty() {
+		var cert []byte
+		if !readUint24LengthPrefixed(&certList, &cert) {
 			return false
 		}
-		s.certificates[i] = data[:certLen]
-		data = data[certLen:]
+		m.certificates = append(m.certificates, cert)
 	}
-
-	return len(data) == 0
+	return s.Empty()
 }
 
 // sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first
@@ -169,6 +137,10 @@ func (m *sessionStateTLS13) unmarshal(data []byte) bool {
 }
 
 func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
+	if len(c.ticketKeys) == 0 {
+		return nil, errors.New("tls: internal error: session ticket keys unavailable")
+	}
+
 	encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size)
 	keyName := encrypted[:ticketKeyNameLen]
 	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
@@ -177,7 +149,7 @@ func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
 	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
 		return nil, err
 	}
-	key := c.config.ticketKeys()[0]
+	key := c.ticketKeys[0]
 	copy(keyName, key.keyName[:])
 	block, err := aes.NewCipher(key.aesKey[:])
 	if err != nil {
@@ -202,19 +174,17 @@ func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey boo
 	macBytes := encrypted[len(encrypted)-sha256.Size:]
 	ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
 
-	keys := c.config.ticketKeys()
 	keyIndex := -1
-	for i, candidateKey := range keys {
+	for i, candidateKey := range c.ticketKeys {
 		if bytes.Equal(keyName, candidateKey.keyName[:]) {
 			keyIndex = i
 			break
 		}
 	}
-
 	if keyIndex == -1 {
 		return nil, false
 	}
-	key := &keys[keyIndex]
+	key := &c.ticketKeys[keyIndex]
 
 	mac := hmac.New(sha256.New, key.hmacKey[:])
 	mac.Write(encrypted[:len(encrypted)-sha256.Size])
@@ -250,9 +220,11 @@ func (c *Conn) getSessionTicketMsg(appData []byte) (*newSessionTicketMsgTLS13, e
 			OCSPStaple:                  c.ocspResponse,
 			SignedCertificateTimestamps: c.scts,
 		},
-		maxEarlyData: c.config.MaxEarlyData,
-		alpn:         c.clientProtocol,
-		appData:      appData,
+		appData: appData,
+		alpn:    c.clientProtocol,
+	}
+	if c.extraConfig != nil {
+		state.maxEarlyData = c.extraConfig.MaxEarlyData
 	}
 	var err error
 	m.label, err = c.encryptTicket(state.marshal())
@@ -260,7 +232,9 @@ func (c *Conn) getSessionTicketMsg(appData []byte) (*newSessionTicketMsgTLS13, e
 		return nil, err
 	}
 	m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
-	m.maxEarlyData = c.config.MaxEarlyData
+	if c.extraConfig != nil {
+		m.maxEarlyData = c.extraConfig.MaxEarlyData
+	}
 	return m, nil
 }
 
@@ -270,7 +244,7 @@ func (c *Conn) getSessionTicketMsg(appData []byte) (*newSessionTicketMsgTLS13, e
 // The ticket may be nil if config.SessionTicketsDisabled is set,
 // or if the client isn't able to receive session tickets.
 func (c *Conn) GetSessionTicket(appData []byte) ([]byte, error) {
-	if c.isClient || !c.handshakeComplete() || c.config.AlternativeRecordLayer == nil {
+	if c.isClient || !c.handshakeComplete() || c.extraConfig == nil || c.extraConfig.AlternativeRecordLayer == nil {
 		return nil, errors.New("GetSessionTicket is only valid for servers after completion of the handshake, and if an alternative record layer is set.")
 	}
 	if c.config.SessionTicketsDisabled {

+ 112 - 29
vendor/github.com/Psiphon-Labs/qtls/tls.go → vendor/github.com/Psiphon-Labs/qtls-go1-16/tls.go

@@ -4,7 +4,6 @@
 
 // package qtls partially implements TLS 1.2, as specified in RFC 5246,
 // and TLS 1.3, as specified in RFC 8446.
-
 package qtls
 
 // BUG(agl): The crypto/tls package only implements some countermeasures
@@ -14,6 +13,7 @@ package qtls
 
 import (
 	"bytes"
+	"context"
 	"crypto"
 	"crypto/ecdsa"
 	"crypto/ed25519"
@@ -22,8 +22,8 @@ import (
 	"encoding/pem"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"net"
+	"os"
 	"strings"
 	"time"
 )
@@ -32,22 +32,36 @@ import (
 // using conn as the underlying transport.
 // The configuration config must be non-nil and must include
 // at least one certificate or else set GetCertificate.
-func Server(conn net.Conn, config *Config) *Conn {
-	return &Conn{conn: conn, config: config}
+func Server(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
+	c := &Conn{
+		conn:        conn,
+		config:      fromConfig(config),
+		extraConfig: extraConfig,
+	}
+	c.handshakeFn = c.serverHandshake
+	return c
 }
 
 // Client returns a new TLS client side connection
 // using conn as the underlying transport.
 // The config cannot be nil: users must set either ServerName or
 // InsecureSkipVerify in the config.
-func Client(conn net.Conn, config *Config) *Conn {
-	return &Conn{conn: conn, config: config, isClient: true}
+func Client(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
+	c := &Conn{
+		conn:        conn,
+		config:      fromConfig(config),
+		extraConfig: extraConfig,
+		isClient:    true,
+	}
+	c.handshakeFn = c.clientHandshake
+	return c
 }
 
 // A listener implements a network listener (net.Listener) for TLS connections.
 type listener struct {
 	net.Listener
-	config *Config
+	config      *Config
+	extraConfig *ExtraConfig
 }
 
 // Accept waits for and returns the next incoming TLS connection.
@@ -57,17 +71,18 @@ func (l *listener) Accept() (net.Conn, error) {
 	if err != nil {
 		return nil, err
 	}
-	return Server(c, l.config), nil
+	return Server(c, l.config, l.extraConfig), nil
 }
 
 // NewListener creates a Listener which accepts connections from an inner
 // Listener and wraps each connection with Server.
 // The configuration config must be non-nil and must include
 // at least one certificate or else set GetCertificate.
-func NewListener(inner net.Listener, config *Config) net.Listener {
+func NewListener(inner net.Listener, config *Config, extraConfig *ExtraConfig) net.Listener {
 	l := new(listener)
 	l.Listener = inner
 	l.config = config
+	l.extraConfig = extraConfig
 	return l
 }
 
@@ -75,7 +90,7 @@ func NewListener(inner net.Listener, config *Config) net.Listener {
 // 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) {
+func Listen(network, laddr string, config *Config, extraConfig *ExtraConfig) (net.Listener, error) {
 	if config == nil || len(config.Certificates) == 0 &&
 		config.GetCertificate == nil && config.GetConfigForClient == nil {
 		return nil, errors.New("tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config")
@@ -84,7 +99,7 @@ func Listen(network, laddr string, config *Config) (net.Listener, error) {
 	if err != nil {
 		return nil, err
 	}
-	return NewListener(l, config), nil
+	return NewListener(l, config, extraConfig), nil
 }
 
 type timeoutError struct{}
@@ -100,30 +115,36 @@ func (timeoutError) Temporary() bool { return true }
 //
 // DialWithDialer interprets a nil configuration as equivalent to the zero
 // configuration; see the documentation of Config for the defaults.
-func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config, extraConfig *ExtraConfig) (*Conn, error) {
+	return dial(context.Background(), dialer, network, addr, config, extraConfig)
+}
+
+func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config, extraConfig *ExtraConfig) (*Conn, error) {
 	// We want the Timeout and Deadline values from dialer to cover the
 	// whole process: TCP connection and TLS handshake. This means that we
 	// also need to start our own timers now.
-	timeout := dialer.Timeout
+	timeout := netDialer.Timeout
 
-	if !dialer.Deadline.IsZero() {
-		deadlineTimeout := time.Until(dialer.Deadline)
+	if !netDialer.Deadline.IsZero() {
+		deadlineTimeout := time.Until(netDialer.Deadline)
 		if timeout == 0 || deadlineTimeout < timeout {
 			timeout = deadlineTimeout
 		}
 	}
 
-	var errChannel chan error
-
+	// hsErrCh is non-nil if we might not wait for Handshake to complete.
+	var hsErrCh chan error
+	if timeout != 0 || ctx.Done() != nil {
+		hsErrCh = make(chan error, 2)
+	}
 	if timeout != 0 {
-		errChannel = make(chan error, 2)
 		timer := time.AfterFunc(timeout, func() {
-			errChannel <- timeoutError{}
+			hsErrCh <- timeoutError{}
 		})
 		defer timer.Stop()
 	}
 
-	rawConn, err := dialer.Dial(network, addr)
+	rawConn, err := netDialer.DialContext(ctx, network, addr)
 	if err != nil {
 		return nil, err
 	}
@@ -146,16 +167,28 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*
 		config = c
 	}
 
-	conn := Client(rawConn, config)
+	conn := Client(rawConn, config, extraConfig)
 
-	if timeout == 0 {
+	if hsErrCh == nil {
 		err = conn.Handshake()
 	} else {
 		go func() {
-			errChannel <- conn.Handshake()
+			hsErrCh <- conn.Handshake()
 		}()
 
-		err = <-errChannel
+		select {
+		case <-ctx.Done():
+			err = ctx.Err()
+		case err = <-hsErrCh:
+			if err != nil {
+				// If the error was due to the context
+				// closing, prefer the context's error, rather
+				// than some random network teardown error.
+				if e := ctx.Err(); e != nil {
+					err = e
+				}
+			}
+		}
 	}
 
 	if err != nil {
@@ -172,8 +205,58 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*
 // 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)
+func Dial(network, addr string, config *Config, extraConfig *ExtraConfig) (*Conn, error) {
+	return DialWithDialer(new(net.Dialer), network, addr, config, extraConfig)
+}
+
+// Dialer dials TLS connections given a configuration and a Dialer for the
+// underlying connection.
+type Dialer struct {
+	// NetDialer is the optional dialer to use for the TLS connections'
+	// underlying TCP connections.
+	// A nil NetDialer is equivalent to the net.Dialer zero value.
+	NetDialer *net.Dialer
+
+	// Config is the TLS configuration to use for new connections.
+	// A nil configuration is equivalent to the zero
+	// configuration; see the documentation of Config for the
+	// defaults.
+	Config *Config
+
+	ExtraConfig *ExtraConfig
+}
+
+// Dial connects to the given network address and initiates a TLS
+// handshake, returning the resulting TLS connection.
+//
+// The returned Conn, if any, will always be of type *Conn.
+func (d *Dialer) Dial(network, addr string) (net.Conn, error) {
+	return d.DialContext(context.Background(), network, addr)
+}
+
+func (d *Dialer) netDialer() *net.Dialer {
+	if d.NetDialer != nil {
+		return d.NetDialer
+	}
+	return new(net.Dialer)
+}
+
+// DialContext connects to the given network address and initiates a TLS
+// handshake, returning the resulting TLS connection.
+//
+// The provided Context must be non-nil. If the context expires before
+// the connection is complete, an error is returned. Once successfully
+// connected, any expiration of the context will not affect the
+// connection.
+//
+// The returned Conn, if any, will always be of type *Conn.
+func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
+	c, err := dial(ctx, d.netDialer(), network, addr, d.Config, d.ExtraConfig)
+	if err != nil {
+		// Don't return c (a typed nil) in an interface.
+		return nil, err
+	}
+	return c, nil
 }
 
 // LoadX509KeyPair reads and parses a public/private key pair from a pair
@@ -182,11 +265,11 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
 // form a certificate chain. On successful return, Certificate.Leaf will
 // be nil because the parsed form of the certificate is not retained.
 func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
-	certPEMBlock, err := ioutil.ReadFile(certFile)
+	certPEMBlock, err := os.ReadFile(certFile)
 	if err != nil {
 		return Certificate{}, err
 	}
-	keyPEMBlock, err := ioutil.ReadFile(keyFile)
+	keyPEMBlock, err := os.ReadFile(keyFile)
 	if err != nil {
 		return Certificate{}, err
 	}
@@ -288,7 +371,7 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
 }
 
 // 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.
+// 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 {

+ 96 - 0
vendor/github.com/Psiphon-Labs/qtls-go1-16/unsafe.go

@@ -0,0 +1,96 @@
+package qtls
+
+import (
+	"crypto/tls"
+	"reflect"
+	"unsafe"
+)
+
+func init() {
+	if !structsEqual(&tls.ConnectionState{}, &connectionState{}) {
+		panic("qtls.ConnectionState doesn't match")
+	}
+	if !structsEqual(&tls.ClientSessionState{}, &clientSessionState{}) {
+		panic("qtls.ClientSessionState doesn't match")
+	}
+	if !structsEqual(&tls.CertificateRequestInfo{}, &certificateRequestInfo{}) {
+		panic("qtls.CertificateRequestInfo doesn't match")
+	}
+	if !structsEqual(&tls.Config{}, &config{}) {
+		panic("qtls.Config doesn't match")
+	}
+	if !structsEqual(&tls.ClientHelloInfo{}, &clientHelloInfo{}) {
+		panic("qtls.ClientHelloInfo doesn't match")
+	}
+}
+
+func toConnectionState(c connectionState) ConnectionState {
+	return *(*ConnectionState)(unsafe.Pointer(&c))
+}
+
+func toClientSessionState(s *clientSessionState) *ClientSessionState {
+	return (*ClientSessionState)(unsafe.Pointer(s))
+}
+
+func fromClientSessionState(s *ClientSessionState) *clientSessionState {
+	return (*clientSessionState)(unsafe.Pointer(s))
+}
+
+func toCertificateRequestInfo(i *certificateRequestInfo) *CertificateRequestInfo {
+	return (*CertificateRequestInfo)(unsafe.Pointer(i))
+}
+
+func toConfig(c *config) *Config {
+	return (*Config)(unsafe.Pointer(c))
+}
+
+func fromConfig(c *Config) *config {
+	return (*config)(unsafe.Pointer(c))
+}
+
+func toClientHelloInfo(chi *clientHelloInfo) *ClientHelloInfo {
+	return (*ClientHelloInfo)(unsafe.Pointer(chi))
+}
+
+func structsEqual(a, b interface{}) bool {
+	return compare(reflect.ValueOf(a), reflect.ValueOf(b))
+}
+
+func compare(a, b reflect.Value) bool {
+	sa := a.Elem()
+	sb := b.Elem()
+	if sa.NumField() != sb.NumField() {
+		return false
+	}
+	for i := 0; i < sa.NumField(); i++ {
+		fa := sa.Type().Field(i)
+		fb := sb.Type().Field(i)
+		if !reflect.DeepEqual(fa.Index, fb.Index) || fa.Name != fb.Name || fa.Anonymous != fb.Anonymous || fa.Offset != fb.Offset || !reflect.DeepEqual(fa.Type, fb.Type) {
+			if fa.Type.Kind() != fb.Type.Kind() {
+				return false
+			}
+			if fa.Type.Kind() == reflect.Slice {
+				if !compareStruct(fa.Type.Elem(), fb.Type.Elem()) {
+					return false
+				}
+				continue
+			}
+			return false
+		}
+	}
+	return true
+}
+
+func compareStruct(a, b reflect.Type) bool {
+	if a.NumField() != b.NumField() {
+		return false
+	}
+	for i := 0; i < a.NumField(); i++ {
+		fa := a.Field(i)
+		fb := b.Field(i)
+		if !reflect.DeepEqual(fa.Index, fb.Index) || fa.Name != fb.Name || fa.Anonymous != fb.Anonymous || fa.Offset != fb.Offset || !reflect.DeepEqual(fa.Type, fb.Type) {
+			return false
+		}
+	}
+	return true
+}

+ 0 - 90
vendor/github.com/Psiphon-Labs/qtls/alert.go

@@ -1,90 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package qtls
-
-import "strconv"
-
-type alert uint8
-
-// Alert is a TLS alert
-type Alert = alert
-
-const (
-	// alert level
-	alertLevelWarning = 1
-	alertLevelError   = 2
-)
-
-const (
-	alertCloseNotify            alert = 0
-	alertUnexpectedMessage      alert = 10
-	alertBadRecordMAC           alert = 20
-	alertDecryptionFailed       alert = 21
-	alertRecordOverflow         alert = 22
-	alertDecompressionFailure   alert = 30
-	alertHandshakeFailure       alert = 40
-	alertBadCertificate         alert = 42
-	alertUnsupportedCertificate alert = 43
-	alertCertificateRevoked     alert = 44
-	alertCertificateExpired     alert = 45
-	alertCertificateUnknown     alert = 46
-	alertIllegalParameter       alert = 47
-	alertUnknownCA              alert = 48
-	alertAccessDenied           alert = 49
-	alertDecodeError            alert = 50
-	alertDecryptError           alert = 51
-	alertProtocolVersion        alert = 70
-	alertInsufficientSecurity   alert = 71
-	alertInternalError          alert = 80
-	alertInappropriateFallback  alert = 86
-	alertUserCanceled           alert = 90
-	alertNoRenegotiation        alert = 100
-	alertMissingExtension       alert = 109
-	alertUnsupportedExtension   alert = 110
-	alertUnrecognizedName       alert = 112
-	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",
-	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",
-	alertUnrecognizedName:       "unrecognized name",
-	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()
-}

+ 4 - 0
vendor/github.com/Psiphon-Labs/quic-go/Changelog.md

@@ -1,5 +1,9 @@
 # Changelog
 
+## v0.20.0 (unreleased)
+
+- Remove the `quic.Config.HandshakeTimeout`. Introduce a `quic.Config.HandshakeIdleTimeout`.
+
 ## v0.17.1 (2020-06-20)
 
 - Supports QUIC WG draft-29.

+ 4 - 4
vendor/github.com/Psiphon-Labs/quic-go/README.md

@@ -2,23 +2,23 @@
 
 <img src="docs/quic.png" width=303 height=124>
 
-[![Godoc Reference](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/lucas-clemente/quic-go)
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/lucas-clemente/quic-go)](https://pkg.go.dev/github.com/lucas-clemente/quic-go)
 [![Travis Build Status](https://img.shields.io/travis/lucas-clemente/quic-go/master.svg?style=flat-square&label=Travis+build)](https://travis-ci.org/lucas-clemente/quic-go)
 [![CircleCI Build Status](https://img.shields.io/circleci/project/github/lucas-clemente/quic-go.svg?style=flat-square&label=CircleCI+build)](https://circleci.com/gh/lucas-clemente/quic-go)
 [![Windows Build Status](https://img.shields.io/appveyor/ci/lucas-clemente/quic-go/master.svg?style=flat-square&label=windows+build)](https://ci.appveyor.com/project/lucas-clemente/quic-go/branch/master)
 [![Code Coverage](https://img.shields.io/codecov/c/github/lucas-clemente/quic-go/master.svg?style=flat-square)](https://codecov.io/gh/lucas-clemente/quic-go/)
 
-quic-go is an implementation of the [QUIC](https://en.wikipedia.org/wiki/QUIC) protocol in Go. It implements the [IETF QUIC draft-29](https://tools.ietf.org/html/draft-ietf-quic-transport-29) and [draft-32](https://tools.ietf.org/html/draft-ietf-quic-transport-32).
+quic-go is an implementation of the [QUIC](https://en.wikipedia.org/wiki/QUIC) protocol in Go. It implements the [IETF QUIC draft-29](https://tools.ietf.org/html/draft-ietf-quic-transport-29), [draft-32](https://tools.ietf.org/html/draft-ietf-quic-transport-32) and [draft-34](https://tools.ietf.org/html/draft-ietf-quic-transport-34).
 
 ## Version compatibility
 
 Since quic-go is under active development, there's no guarantee that two builds of different commits are interoperable. The QUIC version used in the *master* branch is just a placeholder, and should not be considered stable.
 
-If you want to use quic-go as a library in other projects, please consider using a [tagged release](https://github.com/lucas-clemente/quic-go/releases). These releases expose [experimental QUIC versions](https://github.com/quicwg/base-drafts/wiki/QUIC-Versions), which are guaranteed to be stable.
+When using quic-go as a library, please always use a [tagged release](https://github.com/lucas-clemente/quic-go/releases). Only these releases use the official draft version numbers.
 
 ## Guides
 
-*We currently support Go 1.14+, with [Go modules](https://github.com/golang/go/wiki/Modules) support enabled.*
+*We currently support Go 1.15+, with [Go modules](https://github.com/golang/go/wiki/Modules) support enabled.*
 
 Running tests:
 

+ 2 - 2
vendor/github.com/Psiphon-Labs/quic-go/buffer_pool.go

@@ -56,7 +56,7 @@ func (b *packetBuffer) Len() protocol.ByteCount {
 }
 
 func (b *packetBuffer) putBack() {
-	if cap(b.Data) != int(protocol.MaxReceivePacketSize) {
+	if cap(b.Data) != int(protocol.MaxPacketBufferSize) {
 		panic("putPacketBuffer called with packet of wrong size!")
 	}
 	bufferPool.Put(b)
@@ -74,7 +74,7 @@ func getPacketBuffer() *packetBuffer {
 func init() {
 	bufferPool.New = func() interface{} {
 		return &packetBuffer{
-			Data: make([]byte, 0, protocol.MaxReceivePacketSize),
+			Data: make([]byte, 0, protocol.MaxPacketBufferSize),
 		}
 	}
 }

+ 12 - 12
vendor/github.com/Psiphon-Labs/quic-go/client.go

@@ -116,13 +116,14 @@ func dialAddrContext(
 	return dialContext(ctx, udpConn, udpAddr, addr, tlsConf, config, use0RTT, true)
 }
 
-// Dial establishes a new QUIC connection to a server using a net.PacketConn.
-// If the PacketConn satisfies the ECNCapablePacketConn interface (as a net.UDPConn does), ECN support will be enabled.
-// In this case, ReadMsgUDP will be used instead of ReadFrom to read packets.
-// The same PacketConn can be used for multiple calls to Dial and Listen,
-// QUIC connection IDs are used for demultiplexing the different connections.
-// The host parameter is used for SNI.
-// The tls.Config must define an application protocol (using NextProtos).
+// Dial establishes a new QUIC connection to a server using a net.PacketConn. If
+// the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn
+// does), ECN and packet info support will be enabled. In this case, ReadMsgUDP
+// and WriteMsgUDP will be used instead of ReadFrom and WriteTo to read/write
+// packets. The same PacketConn can be used for multiple calls to Dial and
+// Listen, QUIC connection IDs are used for demultiplexing the different
+// connections. The host parameter is used for SNI. The tls.Config must define
+// an application protocol (using NextProtos).
 func Dial(
 	pconn net.PacketConn,
 	remoteAddr net.Addr,
@@ -204,6 +205,9 @@ func dialContext(
 	if c.config.Tracer != nil {
 		c.tracer = c.config.Tracer.TracerForConnection(protocol.PerspectiveClient, c.destConnID)
 	}
+	if c.tracer != nil {
+		c.tracer.StartedConnection(c.conn.LocalAddr(), c.conn.RemoteAddr(), c.srcConnID, c.destConnID)
+	}
 	if err := c.dial(ctx); err != nil {
 		return nil, err
 	}
@@ -255,7 +259,7 @@ func newClient(
 	c := &client{
 		srcConnID:         srcConnID,
 		destConnID:        destConnID,
-		conn:              newSendConn(pconn, remoteAddr),
+		conn:              newSendPconn(pconn, remoteAddr),
 		createdPacketConn: createdPacketConn,
 		use0RTT:           use0RTT,
 		tlsConf:           tlsConf,
@@ -269,9 +273,6 @@ func newClient(
 
 func (c *client) dial(ctx context.Context) error {
 	c.logger.Infof("Starting new connection to %s (%s -> %s), source connection ID %s, destination connection ID %s, version %s", c.tlsConf.ServerName, c.conn.LocalAddr(), c.conn.RemoteAddr(), c.srcConnID, c.destConnID, c.version)
-	if c.tracer != nil {
-		c.tracer.StartedConnection(c.conn.LocalAddr(), c.conn.RemoteAddr(), c.version, c.srcConnID, c.destConnID)
-	}
 
 	c.session = newClientSession(
 		c.conn,
@@ -281,7 +282,6 @@ func (c *client) dial(ctx context.Context) error {
 		c.config,
 		c.tlsConf,
 		c.initialPacketNumber,
-		c.version,
 		c.use0RTT,
 		c.hasNegotiatedVersion,
 		c.tracer,

+ 0 - 1
vendor/github.com/Psiphon-Labs/quic-go/codecov.yml

@@ -12,7 +12,6 @@ coverage:
     - internal/utils/newconnectionid_linkedlist.go
     - internal/utils/packetinterval_linkedlist.go
     - internal/utils/linkedlist/linkedlist.go
-    - quictrace/
     - fuzzing/
     - metrics/
   status:

+ 41 - 23
vendor/github.com/Psiphon-Labs/quic-go/config.go

@@ -2,8 +2,11 @@ package quic
 
 import (
 	"errors"
+	"time"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
+
+	"github.com/Psiphon-Labs/quic-go/internal/utils"
 )
 
 // Clone clones a Config
@@ -12,6 +15,10 @@ func (c *Config) Clone() *Config {
 	return &copy
 }
 
+func (c *Config) handshakeTimeout() time.Duration {
+	return utils.MaxDuration(protocol.DefaultHandshakeTimeout, 2*c.HandshakeIdleTimeout)
+}
+
 func validateConfig(config *Config) error {
 	if config == nil {
 		return nil
@@ -56,21 +63,29 @@ func populateConfig(config *Config) *Config {
 	if len(versions) == 0 {
 		versions = protocol.SupportedVersions
 	}
-	handshakeTimeout := protocol.DefaultHandshakeTimeout
-	if config.HandshakeTimeout != 0 {
-		handshakeTimeout = config.HandshakeTimeout
+	handshakeIdleTimeout := protocol.DefaultHandshakeIdleTimeout
+	if config.HandshakeIdleTimeout != 0 {
+		handshakeIdleTimeout = config.HandshakeIdleTimeout
 	}
 	idleTimeout := protocol.DefaultIdleTimeout
 	if config.MaxIdleTimeout != 0 {
 		idleTimeout = config.MaxIdleTimeout
 	}
-	maxReceiveStreamFlowControlWindow := config.MaxReceiveStreamFlowControlWindow
-	if maxReceiveStreamFlowControlWindow == 0 {
-		maxReceiveStreamFlowControlWindow = protocol.DefaultMaxReceiveStreamFlowControlWindow
+	initialStreamReceiveWindow := config.InitialStreamReceiveWindow
+	if initialStreamReceiveWindow == 0 {
+		initialStreamReceiveWindow = protocol.DefaultInitialMaxStreamData
+	}
+	maxStreamReceiveWindow := config.MaxStreamReceiveWindow
+	if maxStreamReceiveWindow == 0 {
+		maxStreamReceiveWindow = protocol.DefaultMaxReceiveStreamFlowControlWindow
+	}
+	initialConnectionReceiveWindow := config.InitialConnectionReceiveWindow
+	if initialConnectionReceiveWindow == 0 {
+		initialConnectionReceiveWindow = protocol.DefaultInitialMaxData
 	}
-	maxReceiveConnectionFlowControlWindow := config.MaxReceiveConnectionFlowControlWindow
-	if maxReceiveConnectionFlowControlWindow == 0 {
-		maxReceiveConnectionFlowControlWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindow
+	maxConnectionReceiveWindow := config.MaxConnectionReceiveWindow
+	if maxConnectionReceiveWindow == 0 {
+		maxConnectionReceiveWindow = protocol.DefaultMaxReceiveConnectionFlowControlWindow
 	}
 	maxIncomingStreams := config.MaxIncomingStreams
 	if maxIncomingStreams == 0 {
@@ -86,20 +101,23 @@ func populateConfig(config *Config) *Config {
 	}
 
 	return &Config{
-		Versions:                              versions,
-		HandshakeTimeout:                      handshakeTimeout,
-		MaxIdleTimeout:                        idleTimeout,
-		AcceptToken:                           config.AcceptToken,
-		KeepAlive:                             config.KeepAlive,
-		MaxReceiveStreamFlowControlWindow:     maxReceiveStreamFlowControlWindow,
-		MaxReceiveConnectionFlowControlWindow: maxReceiveConnectionFlowControlWindow,
-		MaxIncomingStreams:                    maxIncomingStreams,
-		MaxIncomingUniStreams:                 maxIncomingUniStreams,
-		ConnectionIDLength:                    config.ConnectionIDLength,
-		StatelessResetKey:                     config.StatelessResetKey,
-		TokenStore:                            config.TokenStore,
-		QuicTracer:                            config.QuicTracer,
-		Tracer:                                config.Tracer,
+		Versions:                       versions,
+		HandshakeIdleTimeout:           handshakeIdleTimeout,
+		MaxIdleTimeout:                 idleTimeout,
+		AcceptToken:                    config.AcceptToken,
+		KeepAlive:                      config.KeepAlive,
+		InitialStreamReceiveWindow:     initialStreamReceiveWindow,
+		MaxStreamReceiveWindow:         maxStreamReceiveWindow,
+		InitialConnectionReceiveWindow: initialConnectionReceiveWindow,
+		MaxConnectionReceiveWindow:     maxConnectionReceiveWindow,
+		MaxIncomingStreams:             maxIncomingStreams,
+		MaxIncomingUniStreams:          maxIncomingUniStreams,
+		ConnectionIDLength:             config.ConnectionIDLength,
+		StatelessResetKey:              config.StatelessResetKey,
+		TokenStore:                     config.TokenStore,
+		EnableDatagrams:                config.EnableDatagrams,
+		DisablePathMTUDiscovery:        config.DisablePathMTUDiscovery,
+		Tracer:                         config.Tracer,
 
 		// [Psiphon]
 		ClientHelloSeed: config.ClientHelloSeed,

+ 11 - 6
vendor/github.com/Psiphon-Labs/quic-go/conn.go

@@ -12,23 +12,24 @@ import (
 
 type connection interface {
 	ReadPacket() (*receivedPacket, error)
-	WriteTo([]byte, net.Addr) (int, error)
+	WritePacket(b []byte, addr net.Addr, oob []byte) (int, error)
 	LocalAddr() net.Addr
 	io.Closer
 }
 
 // If the PacketConn passed to Dial or Listen satisfies this interface, quic-go will read the ECN bits from the IP header.
 // In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets.
-type ECNCapablePacketConn interface {
+type OOBCapablePacketConn interface {
 	net.PacketConn
 	SyscallConn() (syscall.RawConn, error)
 	ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
+	WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
 }
 
-var _ ECNCapablePacketConn = &net.UDPConn{}
+var _ OOBCapablePacketConn = &net.UDPConn{}
 
 func wrapConn(pc net.PacketConn) (connection, error) {
-	c, ok := pc.(ECNCapablePacketConn)
+	c, ok := pc.(OOBCapablePacketConn)
 	if !ok {
 		utils.DefaultLogger.Infof("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections.")
 		return &basicConn{PacketConn: pc}, nil
@@ -44,9 +45,9 @@ var _ connection = &basicConn{}
 
 func (c *basicConn) ReadPacket() (*receivedPacket, error) {
 	buffer := getPacketBuffer()
-	// The packet size should not exceed protocol.MaxReceivePacketSize bytes
+	// The packet size should not exceed protocol.MaxPacketBufferSize bytes
 	// If it does, we only read a truncated packet, which will then end up undecryptable
-	buffer.Data = buffer.Data[:protocol.MaxReceivePacketSize]
+	buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize]
 	n, addr, err := c.PacketConn.ReadFrom(buffer.Data)
 	if err != nil {
 		return nil, err
@@ -58,3 +59,7 @@ func (c *basicConn) ReadPacket() (*receivedPacket, error) {
 		buffer:     buffer,
 	}, nil
 }
+
+func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte) (n int, err error) {
+	return c.PacketConn.WriteTo(b, addr)
+}

+ 0 - 113
vendor/github.com/Psiphon-Labs/quic-go/conn_ecn.go

@@ -1,113 +0,0 @@
-// +build darwin linux
-
-package quic
-
-import (
-	"errors"
-	"fmt"
-	"net"
-	"syscall"
-	"time"
-
-	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
-)
-
-const ecnMask uint8 = 0x3
-
-func inspectReadBuffer(c net.PacketConn) (int, error) {
-	conn, ok := c.(interface {
-		SyscallConn() (syscall.RawConn, error)
-	})
-	if !ok {
-		return 0, errors.New("doesn't have a SyscallConn")
-	}
-	rawConn, err := conn.SyscallConn()
-	if err != nil {
-		return 0, fmt.Errorf("couldn't get syscall.RawConn: %w", err)
-	}
-	var size int
-	var serr error
-	if err := rawConn.Control(func(fd uintptr) {
-		size, serr = syscall.GetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF)
-	}); err != nil {
-		return 0, err
-	}
-	return size, serr
-}
-
-type ecnConn struct {
-	ECNCapablePacketConn
-	oobBuffer []byte
-}
-
-var _ connection = &ecnConn{}
-
-func newConn(c ECNCapablePacketConn) (*ecnConn, error) {
-	rawConn, err := c.SyscallConn()
-	if err != nil {
-		return nil, err
-	}
-	// We don't know if this a IPv4-only, IPv6-only or a IPv4-and-IPv6 connection.
-	// Try enabling receiving of ECN for both IP versions.
-	// We expect at least one of those syscalls to succeed.
-	var errIPv4, errIPv6 error
-	if err := rawConn.Control(func(fd uintptr) {
-		errIPv4 = setRECVTOS(fd)
-	}); err != nil {
-		return nil, err
-	}
-	if err := rawConn.Control(func(fd uintptr) {
-		errIPv6 = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IPV6, syscall.IPV6_RECVTCLASS, 1)
-	}); err != nil {
-		return nil, err
-	}
-	switch {
-	case errIPv4 == nil && errIPv6 == nil:
-		utils.DefaultLogger.Debugf("Activating reading of ECN bits for IPv4 and IPv6.")
-	case errIPv4 == nil && errIPv6 != nil:
-		utils.DefaultLogger.Debugf("Activating reading of ECN bits for IPv4.")
-	case errIPv4 != nil && errIPv6 == nil:
-		utils.DefaultLogger.Debugf("Activating reading of ECN bits for IPv6.")
-	case errIPv4 != nil && errIPv6 != nil:
-		return nil, errors.New("activating ECN failed for both IPv4 and IPv6")
-	}
-	return &ecnConn{
-		ECNCapablePacketConn: c,
-		oobBuffer:            make([]byte, 128),
-	}, nil
-}
-
-func (c *ecnConn) ReadPacket() (*receivedPacket, error) {
-	buffer := getPacketBuffer()
-	// The packet size should not exceed protocol.MaxReceivePacketSize bytes
-	// If it does, we only read a truncated packet, which will then end up undecryptable
-	buffer.Data = buffer.Data[:protocol.MaxReceivePacketSize]
-	c.oobBuffer = c.oobBuffer[:cap(c.oobBuffer)]
-	n, oobn, _, addr, err := c.ECNCapablePacketConn.ReadMsgUDP(buffer.Data, c.oobBuffer)
-	if err != nil {
-		return nil, err
-	}
-	ctrlMsgs, err := syscall.ParseSocketControlMessage(c.oobBuffer[:oobn])
-	if err != nil {
-		return nil, err
-	}
-	var ecn protocol.ECN
-	for _, ctrlMsg := range ctrlMsgs {
-		if ctrlMsg.Header.Level == syscall.IPPROTO_IP && ctrlMsg.Header.Type == msgTypeIPTOS {
-			ecn = protocol.ECN(ctrlMsg.Data[0] & ecnMask)
-			break
-		}
-		if ctrlMsg.Header.Level == syscall.IPPROTO_IPV6 && ctrlMsg.Header.Type == syscall.IPV6_TCLASS {
-			ecn = protocol.ECN(ctrlMsg.Data[0] & ecnMask)
-			break
-		}
-	}
-	return &receivedPacket{
-		remoteAddr: addr,
-		rcvTime:    time.Now(),
-		data:       buffer.Data[:n],
-		ecn:        ecn,
-		buffer:     buffer,
-	}, nil
-}

+ 4 - 2
vendor/github.com/Psiphon-Labs/quic-go/conn_generic.go

@@ -1,4 +1,4 @@
-// +build !darwin,!linux,!windows
+// +build !darwin,!linux,!freebsd,!windows
 
 package quic
 
@@ -8,6 +8,8 @@ func newConn(c net.PacketConn) (connection, error) {
 	return &basicConn{PacketConn: c}, nil
 }
 
-func inspectReadBuffer(net.PacketConn) (int, error) {
+func inspectReadBuffer(interface{}) (int, error) {
 	return 0, nil
 }
+
+func (i *packetInfo) OOB() []byte { return nil }

+ 9 - 7
vendor/github.com/Psiphon-Labs/quic-go/conn_helper_darwin.go

@@ -2,14 +2,16 @@
 
 package quic
 
-import "syscall"
+import "golang.org/x/sys/unix"
+
+const msgTypeIPTOS = unix.IP_RECVTOS
 
 const (
-	//nolint:stylecheck
-	ip_recvtos   = 27
-	msgTypeIPTOS = ip_recvtos
+	ipv4RECVPKTINFO = unix.IP_RECVPKTINFO
+	ipv6RECVPKTINFO = 0x3d
 )
 
-func setRECVTOS(fd uintptr) error {
-	return syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, ip_recvtos, 1)
-}
+const (
+	msgTypeIPv4PKTINFO = unix.IP_PKTINFO
+	msgTypeIPv6PKTINFO = 0x2e
+)

+ 17 - 0
vendor/github.com/Psiphon-Labs/quic-go/conn_helper_freebsd.go

@@ -0,0 +1,17 @@
+// +build freebsd
+
+package quic
+
+import "golang.org/x/sys/unix"
+
+const msgTypeIPTOS = unix.IP_RECVTOS
+
+const (
+	ipv4RECVPKTINFO = 0x7
+	ipv6RECVPKTINFO = 0x24
+)
+
+const (
+	msgTypeIPv4PKTINFO = 0x7
+	msgTypeIPv6PKTINFO = 0x2e
+)

+ 11 - 5
vendor/github.com/Psiphon-Labs/quic-go/conn_helper_linux.go

@@ -2,10 +2,16 @@
 
 package quic
 
-import "syscall"
+import "golang.org/x/sys/unix"
 
-const msgTypeIPTOS = syscall.IP_TOS
+const msgTypeIPTOS = unix.IP_TOS
 
-func setRECVTOS(fd uintptr) error {
-	return syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_RECVTOS, 1)
-}
+const (
+	ipv4RECVPKTINFO = unix.IP_PKTINFO
+	ipv6RECVPKTINFO = unix.IPV6_RECVPKTINFO
+)
+
+const (
+	msgTypeIPv4PKTINFO = unix.IP_PKTINFO
+	msgTypeIPv6PKTINFO = unix.IPV6_PKTINFO
+)

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

@@ -63,7 +63,7 @@ func (m *connIDGenerator) SetMaxActiveConnIDs(limit uint64) error {
 	// transport parameter.
 	// We currently don't send the preferred_address transport parameter,
 	// so we can issue (limit - 1) connection IDs.
-	for i := uint64(1); i < utils.MinUint64(limit, protocol.MaxIssuedConnectionIDs); i++ {
+	for i := uint64(len(m.activeSrcConnIDs)); i < utils.MinUint64(limit, protocol.MaxIssuedConnectionIDs); i++ {
 		if err := m.issueNewConnID(); err != nil {
 			return err
 		}

+ 4 - 11
vendor/github.com/Psiphon-Labs/quic-go/conn_id_manager.go

@@ -1,10 +1,7 @@
 package quic
 
 import (
-	"crypto/rand"
-	"encoding/binary"
 	"fmt"
-	mrand "math/rand"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/internal/qerr"
@@ -24,9 +21,9 @@ type connIDManager struct {
 	// We change the connection ID after sending on average
 	// protocol.PacketsPerConnectionID packets. The actual value is randomized
 	// hide the packet loss rate from on-path observers.
-	packetsSinceLastChange uint64
-	rand                   *mrand.Rand
-	packetsPerConnectionID uint64
+	rand                   utils.Rand
+	packetsSinceLastChange uint32
+	packetsPerConnectionID uint32
 
 	addStatelessResetToken    func(protocol.StatelessResetToken)
 	removeStatelessResetToken func(protocol.StatelessResetToken)
@@ -39,15 +36,11 @@ func newConnIDManager(
 	removeStatelessResetToken func(protocol.StatelessResetToken),
 	queueControlFrame func(wire.Frame),
 ) *connIDManager {
-	b := make([]byte, 8)
-	_, _ = rand.Read(b) // ignore the error here. Nothing bad will happen if the seed is not perfectly random.
-	seed := int64(binary.BigEndian.Uint64(b))
 	return &connIDManager{
 		activeConnectionID:        initialDestConnID,
 		addStatelessResetToken:    addStatelessResetToken,
 		removeStatelessResetToken: removeStatelessResetToken,
 		queueControlFrame:         queueControlFrame,
-		rand:                      mrand.New(mrand.NewSource(seed)),
 	}
 }
 
@@ -155,7 +148,7 @@ func (h *connIDManager) updateConnectionID() {
 	h.activeConnectionID = front.ConnectionID
 	h.activeStatelessResetToken = &front.StatelessResetToken
 	h.packetsSinceLastChange = 0
-	h.packetsPerConnectionID = protocol.PacketsPerConnectionID/2 + uint64(h.rand.Int63n(protocol.PacketsPerConnectionID))
+	h.packetsPerConnectionID = protocol.PacketsPerConnectionID/2 + uint32(h.rand.Int31n(protocol.PacketsPerConnectionID))
 	h.addStatelessResetToken(*h.activeStatelessResetToken)
 }
 

+ 235 - 0
vendor/github.com/Psiphon-Labs/quic-go/conn_oob.go

@@ -0,0 +1,235 @@
+// +build darwin linux freebsd
+
+package quic
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"net"
+	"runtime"
+	"syscall"
+	"time"
+	"unsafe"
+
+	"golang.org/x/sys/unix"
+
+	"github.com/Psiphon-Labs/quic-go/internal/protocol"
+	"github.com/Psiphon-Labs/quic-go/internal/utils"
+)
+
+const ecnMask uint8 = 0x3
+
+func inspectReadBuffer(c interface{}) (int, error) {
+	conn, ok := c.(interface {
+		SyscallConn() (syscall.RawConn, error)
+	})
+	if !ok {
+		return 0, errors.New("doesn't have a SyscallConn")
+	}
+	rawConn, err := conn.SyscallConn()
+	if err != nil {
+		return 0, fmt.Errorf("couldn't get syscall.RawConn: %w", err)
+	}
+	var size int
+	var serr error
+	if err := rawConn.Control(func(fd uintptr) {
+		size, serr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF)
+	}); err != nil {
+		return 0, err
+	}
+	return size, serr
+}
+
+type oobConn struct {
+	OOBCapablePacketConn
+	oobBuffer []byte
+}
+
+var _ connection = &oobConn{}
+
+func newConn(c OOBCapablePacketConn) (*oobConn, error) {
+	rawConn, err := c.SyscallConn()
+	if err != nil {
+		return nil, err
+	}
+	needsPacketInfo := false
+	if udpAddr, ok := c.LocalAddr().(*net.UDPAddr); ok && udpAddr.IP.IsUnspecified() {
+		needsPacketInfo = true
+	}
+	// We don't know if this a IPv4-only, IPv6-only or a IPv4-and-IPv6 connection.
+	// Try enabling receiving of ECN and packet info for both IP versions.
+	// We expect at least one of those syscalls to succeed.
+	var errECNIPv4, errECNIPv6, errPIIPv4, errPIIPv6 error
+	if err := rawConn.Control(func(fd uintptr) {
+		errECNIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_RECVTOS, 1)
+		errECNIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_RECVTCLASS, 1)
+
+		if needsPacketInfo {
+			errPIIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, ipv4RECVPKTINFO, 1)
+			errPIIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, ipv6RECVPKTINFO, 1)
+		}
+	}); err != nil {
+		return nil, err
+	}
+	switch {
+	case errECNIPv4 == nil && errECNIPv6 == nil:
+		utils.DefaultLogger.Debugf("Activating reading of ECN bits for IPv4 and IPv6.")
+	case errECNIPv4 == nil && errECNIPv6 != nil:
+		utils.DefaultLogger.Debugf("Activating reading of ECN bits for IPv4.")
+	case errECNIPv4 != nil && errECNIPv6 == nil:
+		utils.DefaultLogger.Debugf("Activating reading of ECN bits for IPv6.")
+	case errECNIPv4 != nil && errECNIPv6 != nil:
+		return nil, errors.New("activating ECN failed for both IPv4 and IPv6")
+	}
+	if needsPacketInfo {
+		switch {
+		case errPIIPv4 == nil && errPIIPv6 == nil:
+			utils.DefaultLogger.Debugf("Activating reading of packet info for IPv4 and IPv6.")
+		case errPIIPv4 == nil && errPIIPv6 != nil:
+			utils.DefaultLogger.Debugf("Activating reading of packet info bits for IPv4.")
+		case errPIIPv4 != nil && errPIIPv6 == nil:
+			utils.DefaultLogger.Debugf("Activating reading of packet info bits for IPv6.")
+		case errPIIPv4 != nil && errPIIPv6 != nil:
+			return nil, errors.New("activating packet info failed for both IPv4 and IPv6")
+		}
+	}
+	return &oobConn{
+		OOBCapablePacketConn: c,
+		oobBuffer:            make([]byte, 128),
+	}, nil
+}
+
+func (c *oobConn) ReadPacket() (*receivedPacket, error) {
+	buffer := getPacketBuffer()
+	// The packet size should not exceed protocol.MaxPacketBufferSize bytes
+	// If it does, we only read a truncated packet, which will then end up undecryptable
+	buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize]
+	c.oobBuffer = c.oobBuffer[:cap(c.oobBuffer)]
+	n, oobn, _, addr, err := c.OOBCapablePacketConn.ReadMsgUDP(buffer.Data, c.oobBuffer)
+	if err != nil {
+		return nil, err
+	}
+	ctrlMsgs, err := unix.ParseSocketControlMessage(c.oobBuffer[:oobn])
+	if err != nil {
+		return nil, err
+	}
+	var ecn protocol.ECN
+	var destIP net.IP
+	var ifIndex uint32
+	for _, ctrlMsg := range ctrlMsgs {
+		if ctrlMsg.Header.Level == unix.IPPROTO_IP {
+			switch ctrlMsg.Header.Type {
+			case msgTypeIPTOS:
+				ecn = protocol.ECN(ctrlMsg.Data[0] & ecnMask)
+			case msgTypeIPv4PKTINFO:
+				// struct in_pktinfo {
+				// 	unsigned int   ipi_ifindex;  /* Interface index */
+				// 	struct in_addr ipi_spec_dst; /* Local address */
+				// 	struct in_addr ipi_addr;     /* Header Destination
+				// 									address */
+				// };
+				if len(ctrlMsg.Data) == 12 {
+					ifIndex = binary.LittleEndian.Uint32(ctrlMsg.Data)
+					destIP = net.IP(ctrlMsg.Data[8:12])
+				} else if len(ctrlMsg.Data) == 4 {
+					// FreeBSD
+					destIP = net.IP(ctrlMsg.Data)
+				}
+			}
+		}
+		if ctrlMsg.Header.Level == unix.IPPROTO_IPV6 {
+			switch ctrlMsg.Header.Type {
+			case unix.IPV6_TCLASS:
+				ecn = protocol.ECN(ctrlMsg.Data[0] & ecnMask)
+			case msgTypeIPv6PKTINFO:
+				// struct in6_pktinfo {
+				// 	struct in6_addr ipi6_addr;    /* src/dst IPv6 address */
+				// 	unsigned int    ipi6_ifindex; /* send/recv interface index */
+				// };
+				if len(ctrlMsg.Data) == 20 {
+					destIP = net.IP(ctrlMsg.Data[:16])
+					ifIndex = binary.LittleEndian.Uint32(ctrlMsg.Data[16:])
+				}
+			}
+		}
+	}
+	var info *packetInfo
+	if destIP != nil {
+		info = &packetInfo{
+			addr:    destIP,
+			ifIndex: ifIndex,
+		}
+	}
+	return &receivedPacket{
+		remoteAddr: addr,
+		rcvTime:    time.Now(),
+		data:       buffer.Data[:n],
+		ecn:        ecn,
+		info:       info,
+		buffer:     buffer,
+	}, nil
+}
+
+func (c *oobConn) WritePacket(b []byte, addr net.Addr, oob []byte) (n int, err error) {
+	n, _, err = c.OOBCapablePacketConn.WriteMsgUDP(b, oob, addr.(*net.UDPAddr))
+	return n, err
+}
+
+func (info *packetInfo) OOB() []byte {
+	if info == nil {
+		return nil
+	}
+	if ip4 := info.addr.To4(); ip4 != nil {
+		// struct in_pktinfo {
+		// 	unsigned int   ipi_ifindex;  /* Interface index */
+		// 	struct in_addr ipi_spec_dst; /* Local address */
+		// 	struct in_addr ipi_addr;     /* Header Destination address */
+		// };
+		msgLen := 12
+		if runtime.GOOS == "freebsd" {
+			msgLen = 4
+		}
+		cmsglen := cmsgLen(msgLen)
+		oob := make([]byte, cmsglen)
+		cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[0]))
+		cmsg.Level = syscall.IPPROTO_TCP
+		cmsg.Type = msgTypeIPv4PKTINFO
+		cmsg.SetLen(cmsglen)
+		off := cmsgLen(0)
+		if runtime.GOOS != "freebsd" {
+			// FreeBSD does not support in_pktinfo, just an in_addr is sent
+			binary.LittleEndian.PutUint32(oob[off:], info.ifIndex)
+			off += 4
+		}
+		copy(oob[off:], ip4)
+		return oob
+	} else if len(info.addr) == 16 {
+		// struct in6_pktinfo {
+		// 	struct in6_addr ipi6_addr;    /* src/dst IPv6 address */
+		// 	unsigned int    ipi6_ifindex; /* send/recv interface index */
+		// };
+		const msgLen = 20
+		cmsglen := cmsgLen(msgLen)
+		oob := make([]byte, cmsglen)
+		cmsg := (*syscall.Cmsghdr)(unsafe.Pointer(&oob[0]))
+		cmsg.Level = syscall.IPPROTO_IPV6
+		cmsg.Type = msgTypeIPv6PKTINFO
+		cmsg.SetLen(cmsglen)
+		off := cmsgLen(0)
+		off += copy(oob[off:], info.addr)
+		binary.LittleEndian.PutUint32(oob[off:], info.ifIndex)
+		return oob
+	}
+	return nil
+}
+
+func cmsgLen(datalen int) int {
+	return cmsgAlign(syscall.SizeofCmsghdr) + datalen
+}
+
+func cmsgAlign(salen int) int {
+	const sizeOfPtr = 0x8
+	salign := sizeOfPtr
+	return (salen + salign - 1) & ^(salign - 1)
+}

+ 3 - 1
vendor/github.com/Psiphon-Labs/quic-go/conn_windows.go

@@ -29,9 +29,11 @@ func inspectReadBuffer(c net.PacketConn) (int, error) {
 	var size int
 	var serr error
 	if err := rawConn.Control(func(fd uintptr) {
-		size, serr = windows.GetsockoptInt(windows.Handle(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF)
+		size, serr = windows.GetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_RCVBUF)
 	}); err != nil {
 		return 0, err
 	}
 	return size, serr
 }
+
+func (i *packetInfo) OOB() []byte { return nil }

+ 87 - 0
vendor/github.com/Psiphon-Labs/quic-go/datagram_queue.go

@@ -0,0 +1,87 @@
+package quic
+
+import (
+	"github.com/Psiphon-Labs/quic-go/internal/protocol"
+	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/internal/wire"
+)
+
+type datagramQueue struct {
+	sendQueue chan *wire.DatagramFrame
+	rcvQueue  chan []byte
+
+	closeErr error
+	closed   chan struct{}
+
+	hasData func()
+
+	dequeued chan struct{}
+
+	logger utils.Logger
+}
+
+func newDatagramQueue(hasData func(), logger utils.Logger) *datagramQueue {
+	return &datagramQueue{
+		hasData:   hasData,
+		sendQueue: make(chan *wire.DatagramFrame, 1),
+		rcvQueue:  make(chan []byte, protocol.DatagramRcvQueueLen),
+		dequeued:  make(chan struct{}),
+		closed:    make(chan struct{}),
+		logger:    logger,
+	}
+}
+
+// AddAndWait queues a new DATAGRAM frame for sending.
+// It blocks until the frame has been dequeued.
+func (h *datagramQueue) AddAndWait(f *wire.DatagramFrame) error {
+	select {
+	case h.sendQueue <- f:
+		h.hasData()
+	case <-h.closed:
+		return h.closeErr
+	}
+
+	select {
+	case <-h.dequeued:
+		return nil
+	case <-h.closed:
+		return h.closeErr
+	}
+}
+
+// Get dequeues a DATAGRAM frame for sending.
+func (h *datagramQueue) Get() *wire.DatagramFrame {
+	select {
+	case f := <-h.sendQueue:
+		h.dequeued <- struct{}{}
+		return f
+	default:
+		return nil
+	}
+}
+
+// HandleDatagramFrame handles a received DATAGRAM frame.
+func (h *datagramQueue) HandleDatagramFrame(f *wire.DatagramFrame) {
+	data := make([]byte, len(f.Data))
+	copy(data, f.Data)
+	select {
+	case h.rcvQueue <- data:
+	default:
+		h.logger.Debugf("Discarding DATAGRAM frame (%d bytes payload)", len(f.Data))
+	}
+}
+
+// Receive gets a received DATAGRAM frame.
+func (h *datagramQueue) Receive() ([]byte, error) {
+	select {
+	case data := <-h.rcvQueue:
+		return data, nil
+	case <-h.closed:
+		return nil, h.closeErr
+	}
+}
+
+func (h *datagramQueue) CloseWithError(e error) {
+	h.closeErr = e
+	close(h.closed)
+}

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

@@ -1,12 +1,13 @@
 package quic
 
 import (
+	"errors"
 	"sync"
 
 	"github.com/Psiphon-Labs/quic-go/internal/ackhandler"
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
 	"github.com/Psiphon-Labs/quic-go/internal/wire"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 type framer interface {
@@ -17,6 +18,8 @@ type framer interface {
 
 	AddActiveStream(protocol.StreamID)
 	AppendStreamFrames([]ackhandler.Frame, protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount)
+
+	Handle0RTTRejection() error
 }
 
 type framerI struct {
@@ -114,7 +117,7 @@ func (f *framerI) AppendStreamFrames(frames []ackhandler.Frame, maxLen protocol.
 		// For the last STREAM frame, we'll remove the DataLen field later.
 		// Therefore, we can pretend to have more bytes available when popping
 		// the STREAM frame (which will always have the DataLen set).
-		remainingLen += utils.VarIntLen(uint64(remainingLen))
+		remainingLen += quicvarint.Len(uint64(remainingLen))
 		frame, hasMoreData := str.popStreamFrame(remainingLen)
 		if hasMoreData { // put the stream back in the queue (at the end)
 			f.streamQueue = append(f.streamQueue, id)
@@ -140,3 +143,29 @@ func (f *framerI) AppendStreamFrames(frames []ackhandler.Frame, maxLen protocol.
 	}
 	return frames, length
 }
+
+func (f *framerI) Handle0RTTRejection() error {
+	f.mutex.Lock()
+	defer f.mutex.Unlock()
+
+	f.controlFrameMutex.Lock()
+	f.streamQueue = f.streamQueue[:0]
+	for id := range f.activeStreams {
+		delete(f.activeStreams, id)
+	}
+	var j int
+	for i, frame := range f.controlFrames {
+		switch frame.(type) {
+		case *wire.MaxDataFrame, *wire.MaxStreamDataFrame, *wire.MaxStreamsFrame:
+			return errors.New("didn't expect MAX_DATA / MAX_STREAM_DATA / MAX_STREAMS frame to be sent in 0-RTT")
+		case *wire.DataBlockedFrame, *wire.StreamDataBlockedFrame, *wire.StreamsBlockedFrame:
+			continue
+		default:
+			f.controlFrames[j] = f.controlFrames[i]
+			j++
+		}
+	}
+	f.controlFrames = f.controlFrames[:j]
+	f.controlFrameMutex.Unlock()
+	return nil
+}

+ 4 - 8
vendor/github.com/Psiphon-Labs/quic-go/go.mod

@@ -5,19 +5,15 @@ go 1.14
 require (
 	github.com/cheekybits/genny v1.0.0
 	github.com/francoispqt/gojay v1.2.13
-	github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 // indirect
-	github.com/golang/mock v1.4.4
-	github.com/golang/protobuf v1.4.2
+	github.com/golang/mock v1.5.0
 	github.com/marten-seemann/qpack v0.2.1
-	github.com/Psiphon-Labs/qtls v0.10.0
-	github.com/Psiphon-Labs/qtls-go1-15 v0.1.1
+	github.com/Psiphon-Labs/qtls-go1-15 v0.1.4
+	github.com/Psiphon-Labs/qtls-go1-16 v0.1.3
 	github.com/onsi/ginkgo v1.14.0
 	github.com/onsi/gomega v1.10.1
-	go.opencensus.io v0.22.2
 	golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
 	golang.org/x/net v0.0.0-20200707034311-ab3426394381
 	golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
-	golang.org/x/sys v0.0.0-20200519105757-fe76b779f299
-	google.golang.org/protobuf v1.23.0
+	golang.org/x/sys v0.0.0-20201231184435-2d18734c6014
 	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
 )

+ 13 - 41
vendor/github.com/Psiphon-Labs/quic-go/go.sum

@@ -16,14 +16,12 @@ github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitf
 github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
 github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@@ -32,25 +30,18 @@ github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aev
 github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE=
-github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg=
-github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
-github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
 github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
@@ -69,7 +60,6 @@ github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE0
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -85,11 +75,10 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm
 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
 github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
-github.com/Psiphon-Labs/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc=
-github.com/Psiphon-Labs/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
-github.com/Psiphon-Labs/qtls-go1-15 v0.1.1 h1:LIH6K34bPVttyXnUWixk0bzH6/N07VxbSabxn5A5gZQ=
-github.com/Psiphon-Labs/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/Psiphon-Labs/qtls-go1-15 v0.1.4 h1:RehYMOyRW8hPVEja1KBVsFVNSm35Jj9Mvs5yNoZZ28A=
+github.com/Psiphon-Labs/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
+github.com/Psiphon-Labs/qtls-go1-16 v0.1.3 h1:XEZ1xGorVy9u+lJq+WXNE+hiqRYLNvJGYmwfwKQN2gU=
+github.com/Psiphon-Labs/qtls-go1-16 v0.1.3/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -139,24 +128,18 @@ github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYED
 github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
 github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
 github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
 github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
 github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
-go.opencensus.io v0.18.0 h1:Mk5rgZcggtbvtAun5aJzAtjKKN/t0R3jJPlWILlv938=
 go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
-go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
-go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
 golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
 golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -164,7 +147,7 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL
 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -174,9 +157,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
@@ -190,7 +171,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -200,18 +180,15 @@ golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
 golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
 golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg=
+golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -222,8 +199,10 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
@@ -238,12 +217,10 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
 google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
 google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -251,18 +228,15 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE
 google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
 google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -270,7 +244,5 @@ grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJd
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
-rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
 sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

+ 82 - 23
vendor/github.com/Psiphon-Labs/quic-go/http3/client.go

@@ -2,6 +2,7 @@ package http3
 
 import (
 	"bytes"
+	"context"
 	"crypto/tls"
 	"errors"
 	"fmt"
@@ -14,6 +15,7 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/internal/qtls"
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 	"github.com/marten-seemann/qpack"
 )
 
@@ -36,6 +38,7 @@ var dialAddr = quic.DialAddrEarly
 
 type roundTripperOpts struct {
 	DisableCompression bool
+	EnableDatagram     bool
 	MaxHeaderBytes     int64
 }
 
@@ -72,7 +75,7 @@ func newClient(
 	dialer func(network, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlySession, error),
 ) (*client, error) {
 	if quicConfig == nil {
-		quicConfig = defaultQuicConfig
+		quicConfig = defaultQuicConfig.Clone()
 	} else if len(quicConfig.Versions) == 0 {
 		quicConfig = quicConfig.Clone()
 		quicConfig.Versions = []quic.VersionNumber{defaultQuicConfig.Versions[0]}
@@ -81,12 +84,8 @@ func newClient(
 		return nil, errors.New("can only use a single QUIC version for dialing a HTTP/3 connection")
 	}
 
-	// [Psiphon]
-	// Avoid race condition the results from concurrent RoundTrippers using
-	// defaultQuicConfig.
-	if quicConfig.MaxIncomingStreams != -1 {
-		quicConfig.MaxIncomingStreams = -1 // don't allow any bidirectional streams
-	}
+	quicConfig.MaxIncomingStreams = -1 // don't allow any bidirectional streams
+	quicConfig.EnableDatagrams = opts.EnableDatagram
 
 	logger := utils.DefaultLogger.WithPrefix("h3 client")
 
@@ -118,6 +117,9 @@ func (c *client) dial() error {
 	} else {
 		session, err = dialAddr(c.hostname, c.tlsConf, c.config)
 	}
+	if err != nil {
+		return err
+	}
 
 	// [Psiphon]
 	c.sessionMutex.Lock()
@@ -129,11 +131,7 @@ func (c *client) dial() error {
 	}
 	c.sessionMutex.Unlock()
 
-	if err != nil {
-		return err
-	}
-
-	// run the sesssion setup using 0-RTT data
+	// send the SETTINGs frame, using 0-RTT data, if possible
 	go func() {
 		if err := c.setupSession(); err != nil {
 			c.logger.Debugf("Setting up session failed: %s", err)
@@ -141,6 +139,7 @@ func (c *client) dial() error {
 		}
 	}()
 
+	go c.handleUnidirectionalStreams()
 	return nil
 }
 
@@ -151,15 +150,63 @@ func (c *client) setupSession() error {
 		return err
 	}
 	buf := &bytes.Buffer{}
-	// write the type byte
-	buf.Write([]byte{0x0})
+	quicvarint.Write(buf, streamTypeControlStream)
 	// send the SETTINGS frame
-	(&settingsFrame{}).Write(buf)
-	if _, err := str.Write(buf.Bytes()); err != nil {
-		return err
-	}
+	(&settingsFrame{Datagram: c.opts.EnableDatagram}).Write(buf)
+	_, err = str.Write(buf.Bytes())
+	return err
+}
 
-	return nil
+func (c *client) handleUnidirectionalStreams() {
+	for {
+		str, err := c.session.AcceptUniStream(context.Background())
+		if err != nil {
+			c.logger.Debugf("accepting unidirectional stream failed: %s", err)
+			return
+		}
+
+		go func() {
+			streamType, err := quicvarint.Read(&byteReaderImpl{str})
+			if err != nil {
+				c.logger.Debugf("reading stream type on stream %d failed: %s", str.StreamID(), err)
+				return
+			}
+			// We're only interested in the control stream here.
+			switch streamType {
+			case streamTypeControlStream:
+			case streamTypeQPACKEncoderStream, streamTypeQPACKDecoderStream:
+				// Our QPACK implementation doesn't use the dynamic table yet.
+				// TODO: check that only one stream of each type is opened.
+				return
+			case streamTypePushStream:
+				// We never increased the Push ID, so we don't expect any push streams.
+				c.session.CloseWithError(quic.ErrorCode(errorIDError), "")
+				return
+			default:
+				str.CancelRead(quic.ErrorCode(errorStreamCreationError))
+				return
+			}
+			f, err := parseNextFrame(str)
+			if err != nil {
+				c.session.CloseWithError(quic.ErrorCode(errorFrameError), "")
+				return
+			}
+			sf, ok := f.(*settingsFrame)
+			if !ok {
+				c.session.CloseWithError(quic.ErrorCode(errorMissingSettings), "")
+				return
+			}
+			if !sf.Datagram {
+				return
+			}
+			// If datagram support was enabled on our side as well as on the server side,
+			// we can expect it to have been negotiated both on the transport and on the HTTP/3 layer.
+			// Note: ConnectionState() will block until the handshake is complete (relevant when using 0-RTT).
+			if c.opts.EnableDatagram && !c.session.ConnectionState().SupportsDatagrams {
+				c.session.CloseWithError(quic.ErrorCode(errorSettingsError), "missing QUIC Datagram support")
+			}
+		}()
+	}
 }
 
 func (c *client) Close() error {
@@ -185,9 +232,6 @@ func (c *client) maxHeaderBytes() uint64 {
 
 // RoundTrip executes a request and returns a response
 func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
-	if req.URL.Scheme != "https" {
-		return nil, errors.New("http3: unsupported scheme")
-	}
 	if authorityAddr("https", hostnameFromRequest(req)) != c.hostname {
 		return nil, fmt.Errorf("http3 client BUG: RoundTrip called for the wrong client (expected %s, got %s)", c.hostname, req.Host)
 	}
@@ -281,7 +325,7 @@ func (c *client) doRequest(
 		return nil, newConnError(errorGeneralProtocolError, err)
 	}
 
-	connState := qtls.ToTLSConnectionState(c.session.ConnectionState())
+	connState := qtls.ToTLSConnectionState(c.session.ConnectionState().TLS)
 	res := &http.Response{
 		Proto:      "HTTP/3",
 		ProtoMajor: 3,
@@ -304,6 +348,21 @@ func (c *client) doRequest(
 	respBody := newResponseBody(str, reqDone, func() {
 		c.session.CloseWithError(quic.ErrorCode(errorFrameUnexpected), "")
 	})
+
+	// Rules for when to set Content-Length are defined in https://tools.ietf.org/html/rfc7230#section-3.3.2.
+	_, hasTransferEncoding := res.Header["Transfer-Encoding"]
+	isInformational := res.StatusCode >= 100 && res.StatusCode < 200
+	isNoContent := res.StatusCode == 204
+	isSuccessfulConnect := req.Method == http.MethodConnect && res.StatusCode >= 200 && res.StatusCode < 300
+	if !hasTransferEncoding && !isInformational && !isNoContent && !isSuccessfulConnect {
+		res.ContentLength = -1
+		if clens, ok := res.Header["Content-Length"]; ok && len(clens) == 1 {
+			if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil {
+				res.ContentLength = clen64
+			}
+		}
+	}
+
 	if requestGzip && res.Header.Get("Content-Encoding") == "gzip" {
 		res.Header.Del("Content-Encoding")
 		res.Header.Del("Content-Length")

+ 3 - 0
vendor/github.com/Psiphon-Labs/quic-go/http3/error_codes.go

@@ -23,6 +23,7 @@ const (
 	errorRequestRejected      errorCode = 0x10b
 	errorRequestCanceled      errorCode = 0x10c
 	errorRequestIncomplete    errorCode = 0x10d
+	errorMessageError         errorCode = 0x10e
 	errorConnectError         errorCode = 0x10f
 	errorVersionFallback      errorCode = 0x110
 )
@@ -57,6 +58,8 @@ func (e errorCode) String() string {
 		return "H3_REQUEST_CANCELLED"
 	case errorRequestIncomplete:
 		return "H3_INCOMPLETE_REQUEST"
+	case errorMessageError:
+		return "H3_MESSAGE_ERROR"
 	case errorConnectError:
 		return "H3_CONNECT_ERROR"
 	case errorVersionFallback:

+ 48 - 21
vendor/github.com/Psiphon-Labs/quic-go/http3/frames.go

@@ -7,7 +7,7 @@ import (
 	"io/ioutil"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 type byteReader interface {
@@ -32,11 +32,11 @@ func parseNextFrame(b io.Reader) (frame, error) {
 	if !ok {
 		br = &byteReaderImpl{b}
 	}
-	t, err := utils.ReadVarInt(br)
+	t, err := quicvarint.Read(br)
 	if err != nil {
 		return nil, err
 	}
-	l, err := utils.ReadVarInt(br)
+	l, err := quicvarint.Read(br)
 	if err != nil {
 		return nil, err
 	}
@@ -72,8 +72,8 @@ type dataFrame struct {
 }
 
 func (f *dataFrame) Write(b *bytes.Buffer) {
-	utils.WriteVarInt(b, 0x0)
-	utils.WriteVarInt(b, f.Length)
+	quicvarint.Write(b, 0x0)
+	quicvarint.Write(b, f.Length)
 }
 
 type headersFrame struct {
@@ -81,12 +81,15 @@ type headersFrame struct {
 }
 
 func (f *headersFrame) Write(b *bytes.Buffer) {
-	utils.WriteVarInt(b, 0x1)
-	utils.WriteVarInt(b, f.Length)
+	quicvarint.Write(b, 0x1)
+	quicvarint.Write(b, f.Length)
 }
 
+const settingDatagram = 0x276
+
 type settingsFrame struct {
-	settings map[uint64]uint64
+	Datagram bool
+	other    map[uint64]uint64 // all settings that we don't explicitly recognize
 }
 
 func parseSettingsFrame(r io.Reader, l uint64) (*settingsFrame, error) {
@@ -100,34 +103,58 @@ func parseSettingsFrame(r io.Reader, l uint64) (*settingsFrame, error) {
 		}
 		return nil, err
 	}
-	frame := &settingsFrame{settings: make(map[uint64]uint64)}
+	frame := &settingsFrame{}
 	b := bytes.NewReader(buf)
+	var readDatagram bool
 	for b.Len() > 0 {
-		id, err := utils.ReadVarInt(b)
+		id, err := quicvarint.Read(b)
 		if err != nil { // should not happen. We allocated the whole frame already.
 			return nil, err
 		}
-		val, err := utils.ReadVarInt(b)
+		val, err := quicvarint.Read(b)
 		if err != nil { // should not happen. We allocated the whole frame already.
 			return nil, err
 		}
-		if _, ok := frame.settings[id]; ok {
-			return nil, fmt.Errorf("duplicate setting: %d", id)
+
+		switch id {
+		case settingDatagram:
+			if readDatagram {
+				return nil, fmt.Errorf("duplicate setting: %d", id)
+			}
+			readDatagram = true
+			if val != 0 && val != 1 {
+				return nil, fmt.Errorf("invalid value for H3_DATAGRAM: %d", val)
+			}
+			frame.Datagram = val == 1
+		default:
+			if _, ok := frame.other[id]; ok {
+				return nil, fmt.Errorf("duplicate setting: %d", id)
+			}
+			if frame.other == nil {
+				frame.other = make(map[uint64]uint64)
+			}
+			frame.other[id] = val
 		}
-		frame.settings[id] = val
 	}
 	return frame, nil
 }
 
 func (f *settingsFrame) Write(b *bytes.Buffer) {
-	utils.WriteVarInt(b, 0x4)
+	quicvarint.Write(b, 0x4)
 	var l protocol.ByteCount
-	for id, val := range f.settings {
-		l += utils.VarIntLen(id) + utils.VarIntLen(val)
+	for id, val := range f.other {
+		l += quicvarint.Len(id) + quicvarint.Len(val)
+	}
+	if f.Datagram {
+		l += quicvarint.Len(settingDatagram) + quicvarint.Len(1)
+	}
+	quicvarint.Write(b, uint64(l))
+	if f.Datagram {
+		quicvarint.Write(b, settingDatagram)
+		quicvarint.Write(b, 1)
 	}
-	utils.WriteVarInt(b, uint64(l))
-	for id, val := range f.settings {
-		utils.WriteVarInt(b, id)
-		utils.WriteVarInt(b, val)
+	for id, val := range f.other {
+		quicvarint.Write(b, id)
+		quicvarint.Write(b, val)
 	}
 }

+ 45 - 15
vendor/github.com/Psiphon-Labs/quic-go/http3/response_writer.go

@@ -3,21 +3,33 @@ package http3
 import (
 	"bufio"
 	"bytes"
-	"io"
 	"net/http"
 	"strconv"
 	"strings"
 
+	"github.com/Psiphon-Labs/quic-go"
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
 	"github.com/marten-seemann/qpack"
 )
 
+// DataStreamer lets the caller take over the stream. After a call to DataStream
+// the HTTP server library will not do anything else with the connection.
+//
+// It becomes the caller's responsibility to manage and close the stream.
+//
+// After a call to DataStream, the original Request.Body must not be used.
+type DataStreamer interface {
+	DataStream() quic.Stream
+}
+
 type responseWriter struct {
-	stream *bufio.Writer
+	stream         quic.Stream // needed for DataStream()
+	bufferedStream *bufio.Writer
 
-	header        http.Header
-	status        int // status code passed to WriteHeader
-	headerWritten bool
+	header         http.Header
+	status         int // status code passed to WriteHeader
+	headerWritten  bool
+	dataStreamUsed bool // set when DataSteam() is called
 
 	logger utils.Logger
 }
@@ -25,13 +37,15 @@ type responseWriter struct {
 var (
 	_ http.ResponseWriter = &responseWriter{}
 	_ http.Flusher        = &responseWriter{}
+	_ DataStreamer        = &responseWriter{}
 )
 
-func newResponseWriter(stream io.Writer, logger utils.Logger) *responseWriter {
+func newResponseWriter(stream quic.Stream, logger utils.Logger) *responseWriter {
 	return &responseWriter{
-		header: http.Header{},
-		stream: bufio.NewWriter(stream),
-		logger: logger,
+		header:         http.Header{},
+		stream:         stream,
+		bufferedStream: bufio.NewWriter(stream),
+		logger:         logger,
 	}
 }
 
@@ -43,7 +57,10 @@ func (w *responseWriter) WriteHeader(status int) {
 	if w.headerWritten {
 		return
 	}
-	w.headerWritten = true
+
+	if status < 100 || status >= 200 {
+		w.headerWritten = true
+	}
 	w.status = status
 
 	var headers bytes.Buffer
@@ -59,12 +76,15 @@ func (w *responseWriter) WriteHeader(status int) {
 	buf := &bytes.Buffer{}
 	(&headersFrame{Length: uint64(headers.Len())}).Write(buf)
 	w.logger.Infof("Responding with %d", status)
-	if _, err := w.stream.Write(buf.Bytes()); err != nil {
+	if _, err := w.bufferedStream.Write(buf.Bytes()); err != nil {
 		w.logger.Errorf("could not write headers frame: %s", err.Error())
 	}
-	if _, err := w.stream.Write(headers.Bytes()); err != nil {
+	if _, err := w.bufferedStream.Write(headers.Bytes()); err != nil {
 		w.logger.Errorf("could not write header frame payload: %s", err.Error())
 	}
+	if !w.headerWritten {
+		w.Flush()
+	}
 }
 
 func (w *responseWriter) Write(p []byte) (int, error) {
@@ -77,18 +97,28 @@ func (w *responseWriter) Write(p []byte) (int, error) {
 	df := &dataFrame{Length: uint64(len(p))}
 	buf := &bytes.Buffer{}
 	df.Write(buf)
-	if _, err := w.stream.Write(buf.Bytes()); err != nil {
+	if _, err := w.bufferedStream.Write(buf.Bytes()); err != nil {
 		return 0, err
 	}
-	return w.stream.Write(p)
+	return w.bufferedStream.Write(p)
 }
 
 func (w *responseWriter) Flush() {
-	if err := w.stream.Flush(); err != nil {
+	if err := w.bufferedStream.Flush(); err != nil {
 		w.logger.Errorf("could not flush to stream: %s", err.Error())
 	}
 }
 
+func (w *responseWriter) usedDataStream() bool {
+	return w.dataStreamUsed
+}
+
+func (w *responseWriter) DataStream() quic.Stream {
+	w.dataStreamUsed = true
+	w.Flush()
+	return w.stream
+}
+
 // copied from http2/http2.go
 // bodyAllowedForStatus reports whether a given response status code
 // permits a body. See RFC 2616, section 4.4.

+ 12 - 5
vendor/github.com/Psiphon-Labs/quic-go/http3/roundtrip.go

@@ -41,6 +41,11 @@ type RoundTripper struct {
 	// If nil, reasonable default values will be used.
 	QuicConfig *quic.Config
 
+	// Enable support for HTTP/3 datagrams.
+	// If set to true, QuicConfig.EnableDatagram will be set.
+	// See https://www.ietf.org/archive/id/draft-schinazi-masque-h3-datagram-02.html.
+	EnableDatagrams bool
+
 	// Dial specifies an optional dial function for creating QUIC
 	// connections for requests.
 	// If Dial is nil, quic.DialAddr will be used.
@@ -56,11 +61,12 @@ type RoundTripper struct {
 
 // RoundTripOpt are options for the Transport.RoundTripOpt method.
 type RoundTripOpt struct {
-	// OnlyCachedConn controls whether the RoundTripper may
-	// create a new QUIC connection. If set true and
-	// no cached connection is available, RoundTrip
-	// will return ErrNoCachedConn.
+	// OnlyCachedConn controls whether the RoundTripper may create a new QUIC connection.
+	// If set true and no cached connection is available, RoundTrip will return ErrNoCachedConn.
 	OnlyCachedConn bool
+	// SkipSchemeCheck controls whether we check if the scheme is https.
+	// This allows the use of different schemes, e.g. masque://target.example.com:443/.
+	SkipSchemeCheck bool
 }
 
 var _ roundTripCloser = &RoundTripper{}
@@ -94,7 +100,7 @@ func (r *RoundTripper) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.
 				}
 			}
 		}
-	} else {
+	} else if !opt.SkipSchemeCheck {
 		closeRequestBody(req)
 		return nil, fmt.Errorf("http3: unsupported protocol scheme: %s", req.URL.Scheme)
 	}
@@ -135,6 +141,7 @@ func (r *RoundTripper) getClient(hostname string, onlyCached bool) (http.RoundTr
 			hostname,
 			r.TLSClientConfig,
 			&roundTripperOpts{
+				EnableDatagram:     r.EnableDatagrams,
 				DisableCompression: r.DisableCompression,
 				MaxHeaderBytes:     r.MaxResponseHeaderBytes,
 			},

+ 107 - 26
vendor/github.com/Psiphon-Labs/quic-go/http3/server.go

@@ -7,7 +7,6 @@ import (
 	"errors"
 	"fmt"
 	"io"
-	"math"
 	"net"
 	"net/http"
 	"runtime"
@@ -20,16 +19,10 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/handshake"
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 	"github.com/marten-seemann/qpack"
 )
 
-func init() {
-	// Chrome compatibility mode:
-	// Chrome 87 doesn't support key updates (support was added in Chrome 88).
-	// Don't initiate key updates to avoid breaking large downloads.
-	handshake.KeyUpdateInterval = math.MaxUint64
-}
-
 // allows mocking of quic.Listen and quic.ListenAddr
 var (
 	quicListen     = quic.ListenEarly
@@ -39,6 +32,14 @@ var (
 const (
 	nextProtoH3Draft29 = "h3-29"
 	nextProtoH3Draft32 = "h3-32"
+	nextProtoH3Draft34 = "h3-34"
+)
+
+const (
+	streamTypeControlStream      = 0
+	streamTypePushStream         = 1
+	streamTypeQPACKEncoderStream = 2
+	streamTypeQPACKDecoderStream = 3
 )
 
 func versionToALPN(v protocol.VersionNumber) string {
@@ -48,6 +49,9 @@ func versionToALPN(v protocol.VersionNumber) string {
 	if v == protocol.VersionDraft32 {
 		return nextProtoH3Draft32
 	}
+	if v == protocol.VersionDraft34 {
+		return nextProtoH3Draft34
+	}
 	return ""
 }
 
@@ -79,7 +83,7 @@ func newConnError(code errorCode, err error) requestError {
 	return requestError{err: err, connErr: code}
 }
 
-// Server is a HTTP2 server listening for QUIC connections.
+// Server is a HTTP/3 server.
 type Server struct {
 	*http.Server
 
@@ -87,6 +91,11 @@ type Server struct {
 	// If nil, it uses reasonable default values.
 	QuicConfig *quic.Config
 
+	// Enable support for HTTP/3 datagrams.
+	// If set to true, QuicConfig.EnableDatagram will be set.
+	// See https://www.ietf.org/archive/id/draft-schinazi-masque-h3-datagram-02.html.
+	EnableDatagrams bool
+
 	port uint32 // used atomically
 
 	mutex     sync.Mutex
@@ -145,8 +154,13 @@ func (s *Server) serveImpl(tlsConf *tls.Config, conn net.PacketConn) error {
 		GetConfigForClient: func(ch *tls.ClientHelloInfo) (*tls.Config, error) {
 			// determine the ALPN from the QUIC version used
 			proto := nextProtoH3Draft29
-			if qconn, ok := ch.Conn.(handshake.ConnWithVersion); ok && qconn.GetQUICVersion() == quic.VersionDraft32 {
-				proto = nextProtoH3Draft32
+			if qconn, ok := ch.Conn.(handshake.ConnWithVersion); ok {
+				if qconn.GetQUICVersion() == quic.VersionDraft32 {
+					proto = nextProtoH3Draft32
+				}
+				if qconn.GetQUICVersion() == protocol.VersionDraft34 {
+					proto = nextProtoH3Draft34
+				}
 			}
 			config := tlsConf
 			if tlsConf.GetConfigForClient != nil {
@@ -171,10 +185,19 @@ func (s *Server) serveImpl(tlsConf *tls.Config, conn net.PacketConn) error {
 
 	var ln quic.EarlyListener
 	var err error
+	quicConf := s.QuicConfig
+	if quicConf == nil {
+		quicConf = &quic.Config{}
+	} else {
+		quicConf = s.QuicConfig.Clone()
+	}
+	if s.EnableDatagrams {
+		quicConf.EnableDatagrams = true
+	}
 	if conn == nil {
-		ln, err = quicListenAddr(s.Addr, baseConf, s.QuicConfig)
+		ln, err = quicListenAddr(s.Addr, baseConf, quicConf)
 	} else {
-		ln, err = quicListen(conn, baseConf, s.QuicConfig)
+		ln, err = quicListen(conn, baseConf, quicConf)
 	}
 	if err != nil {
 		return err
@@ -210,7 +233,6 @@ func (s *Server) removeListener(l *quic.EarlyListener) {
 }
 
 func (s *Server) handleConn(sess quic.EarlySession) {
-	// TODO: accept control streams
 	decoder := qpack.NewDecoder(nil)
 
 	// send a SETTINGS frame
@@ -219,10 +241,13 @@ func (s *Server) handleConn(sess quic.EarlySession) {
 		s.logger.Debugf("Opening the control stream failed.")
 		return
 	}
-	buf := bytes.NewBuffer([]byte{0})
-	(&settingsFrame{}).Write(buf)
+	buf := &bytes.Buffer{}
+	quicvarint.Write(buf, streamTypeControlStream) // stream type
+	(&settingsFrame{Datagram: s.EnableDatagrams}).Write(buf)
 	str.Write(buf.Bytes())
 
+	go s.handleUnidirectionalStreams(sess)
+
 	// Process all requests immediately.
 	// It's the client's responsibility to decide which requests are eligible for 0-RTT.
 	for {
@@ -254,6 +279,57 @@ func (s *Server) handleConn(sess quic.EarlySession) {
 	}
 }
 
+func (s *Server) handleUnidirectionalStreams(sess quic.EarlySession) {
+	for {
+		str, err := sess.AcceptUniStream(context.Background())
+		if err != nil {
+			s.logger.Debugf("accepting unidirectional stream failed: %s", err)
+			return
+		}
+
+		go func(str quic.ReceiveStream) {
+			streamType, err := quicvarint.Read(&byteReaderImpl{str})
+			if err != nil {
+				s.logger.Debugf("reading stream type on stream %d failed: %s", str.StreamID(), err)
+				return
+			}
+			// We're only interested in the control stream here.
+			switch streamType {
+			case streamTypeControlStream:
+			case streamTypeQPACKEncoderStream, streamTypeQPACKDecoderStream:
+				// Our QPACK implementation doesn't use the dynamic table yet.
+				// TODO: check that only one stream of each type is opened.
+				return
+			case streamTypePushStream: // only the server can push
+				sess.CloseWithError(quic.ErrorCode(errorStreamCreationError), "")
+				return
+			default:
+				str.CancelRead(quic.ErrorCode(errorStreamCreationError))
+				return
+			}
+			f, err := parseNextFrame(str)
+			if err != nil {
+				sess.CloseWithError(quic.ErrorCode(errorFrameError), "")
+				return
+			}
+			sf, ok := f.(*settingsFrame)
+			if !ok {
+				sess.CloseWithError(quic.ErrorCode(errorMissingSettings), "")
+				return
+			}
+			if !sf.Datagram {
+				return
+			}
+			// If datagram support was enabled on our side as well as on the client side,
+			// we can expect it to have been negotiated both on the transport and on the HTTP/3 layer.
+			// Note: ConnectionState() will block until the handshake is complete (relevant when using 0-RTT).
+			if s.EnableDatagrams && !sess.ConnectionState().SupportsDatagrams {
+				sess.CloseWithError(quic.ErrorCode(errorSettingsError), "missing QUIC Datagram support")
+			}
+		}(str)
+	}
+}
+
 func (s *Server) maxHeaderBytes() uint64 {
 	if s.Server.MaxHeaderBytes <= 0 {
 		return http.DefaultMaxHeaderBytes
@@ -301,8 +377,12 @@ func (s *Server) handleRequest(sess quic.Session, str quic.Stream, decoder *qpac
 	ctx = context.WithValue(ctx, ServerContextKey, s)
 	ctx = context.WithValue(ctx, http.LocalAddrContextKey, sess.LocalAddr())
 	req = req.WithContext(ctx)
-	responseWriter := newResponseWriter(str, s.logger)
-	defer responseWriter.Flush()
+	r := newResponseWriter(str, s.logger)
+	defer func() {
+		if !r.usedDataStream() {
+			r.Flush()
+		}
+	}()
 	handler := s.Handler
 	if handler == nil {
 		handler = http.DefaultServeMux
@@ -320,17 +400,18 @@ func (s *Server) handleRequest(sess quic.Session, str quic.Stream, decoder *qpac
 				panicked = true
 			}
 		}()
-		handler.ServeHTTP(responseWriter, req)
+		handler.ServeHTTP(r, req)
 	}()
 
-	if panicked {
-		responseWriter.WriteHeader(500)
-	} else {
-		responseWriter.WriteHeader(200)
+	if !r.usedDataStream() {
+		if panicked {
+			r.WriteHeader(500)
+		} else {
+			r.WriteHeader(200)
+		}
+		// If the EOF was read by the handler, CancelRead() is a no-op.
+		str.CancelRead(quic.ErrorCode(errorNoError))
 	}
-
-	// If the EOF was read by the handler, CancelRead() is a no-op.
-	str.CancelRead(quic.ErrorCode(errorNoError))
 	return requestError{}
 }
 

+ 52 - 18
vendor/github.com/Psiphon-Labs/quic-go/interface.go

@@ -2,6 +2,7 @@ package quic
 
 import (
 	"context"
+	"errors"
 	"io"
 	"net"
 	"time"
@@ -10,7 +11,6 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/handshake"
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/logging"
-	"github.com/Psiphon-Labs/quic-go/quictrace"
 )
 
 // RetireBugBackwardsCompatibilityMode controls a backwards compatibility mode, necessary due to a bug in
@@ -34,6 +34,8 @@ const (
 	VersionDraft29 = protocol.VersionDraft29
 	// VersionDraft32 is IETF QUIC draft-32
 	VersionDraft32 = protocol.VersionDraft32
+	// VersionDraft34 is IETF QUIC draft-34
+	VersionDraft34 = protocol.VersionDraft34
 )
 
 // A Token can be used to verify the ownership of the client address.
@@ -67,6 +69,13 @@ type TokenStore interface {
 // Valid values range between 0 and MAX_UINT62.
 type ErrorCode = protocol.ApplicationErrorCode
 
+// Err0RTTRejected is the returned from:
+// * Open{Uni}Stream{Sync}
+// * Accept{Uni}Stream
+// * Stream.Read and Stream.Write
+// when the server rejects a 0-RTT connection attempt.
+var Err0RTTRejected = errors.New("0-RTT rejected")
+
 // Stream is the interface implemented by QUIC streams
 type Stream interface {
 	ReceiveStream
@@ -143,8 +152,6 @@ type StreamError interface {
 	ErrorCode() ErrorCode
 }
 
-type ConnectionState = handshake.ConnectionState
-
 // A Session is a QUIC connection between two peers.
 type Session interface {
 	// AcceptStream returns the next stream opened by the peer, blocking until one is available.
@@ -191,6 +198,13 @@ type Session interface {
 	// It blocks until the handshake completes.
 	// Warning: This API should not be considered stable and might change soon.
 	ConnectionState() ConnectionState
+
+	// SendMessage sends a message as a datagram.
+	// See https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
+	SendMessage([]byte) error
+	// ReceiveMessage gets a message received in a datagram.
+	// See https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
+	ReceiveMessage() ([]byte, error)
 }
 
 // An EarlySession is a session that is handshaking.
@@ -204,6 +218,8 @@ type EarlySession interface {
 	// Data sent before completion of the handshake is encrypted with 1-RTT keys.
 	// Note that the client's identity hasn't been verified yet.
 	HandshakeComplete() context.Context
+
+	NextSession() Session
 }
 
 // Config contains all configuration data needed for a QUIC server or client.
@@ -219,10 +235,10 @@ type Config struct {
 	// If used for a server, or dialing on a packet conn, a 4 byte connection ID will be used.
 	// When dialing on a packet conn, the ConnectionIDLength value must be the same for every Dial call.
 	ConnectionIDLength int
-	// HandshakeTimeout is the maximum duration that the cryptographic handshake may take.
-	// If the timeout is exceeded, the connection is closed.
-	// If this value is zero, the timeout is set to 10 seconds.
-	HandshakeTimeout time.Duration
+	// HandshakeIdleTimeout is the idle timeout before completion of the handshake.
+	// Specifically, if we don't receive any packet from the peer within this time, the connection attempt is aborted.
+	// If this value is zero, the timeout is set to 5 seconds.
+	HandshakeIdleTimeout time.Duration
 	// MaxIdleTimeout is the maximum duration that may pass without any incoming network activity.
 	// The actual value for the idle timeout is the minimum of this value and the peer's.
 	// This value only applies after the handshake has completed.
@@ -242,12 +258,22 @@ type Config struct {
 	// The key used to store tokens is the ServerName from the tls.Config, if set
 	// otherwise the token is associated with the server's IP address.
 	TokenStore TokenStore
-	// MaxReceiveStreamFlowControlWindow is the maximum stream-level flow control window for receiving data.
-	// If this value is zero, it will default to 1 MB for the server and 6 MB for the client.
-	MaxReceiveStreamFlowControlWindow uint64
-	// MaxReceiveConnectionFlowControlWindow is the connection-level flow control window for receiving data.
-	// If this value is zero, it will default to 1.5 MB for the server and 15 MB for the client.
-	MaxReceiveConnectionFlowControlWindow uint64
+	// InitialStreamReceiveWindow is the initial size of the stream-level flow control window for receiving data.
+	// If the application is consuming data quickly enough, the flow control auto-tuning algorithm
+	// will increase the window up to MaxStreamReceiveWindow.
+	// If this value is zero, it will default to 512 KB.
+	InitialStreamReceiveWindow uint64
+	// MaxStreamReceiveWindow is the maximum stream-level flow control window for receiving data.
+	// If this value is zero, it will default to 6 MB.
+	MaxStreamReceiveWindow uint64
+	// InitialConnectionReceiveWindow is the initial size of the stream-level flow control window for receiving data.
+	// If the application is consuming data quickly enough, the flow control auto-tuning algorithm
+	// will increase the window up to MaxConnectionReceiveWindow.
+	// If this value is zero, it will default to 512 KB.
+	InitialConnectionReceiveWindow uint64
+	// MaxConnectionReceiveWindow is the connection-level flow control window for receiving data.
+	// If this value is zero, it will default to 15 MB.
+	MaxConnectionReceiveWindow uint64
 	// MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
 	// Values above 2^60 are invalid.
 	// If not set, it will default to 100.
@@ -263,17 +289,25 @@ type Config struct {
 	StatelessResetKey []byte
 	// KeepAlive defines whether this peer will periodically send a packet to keep the connection alive.
 	KeepAlive bool
-	// QUIC Event Tracer (see https://github.com/google/quic-trace).
-	// Warning: Support for quic-trace will soon be dropped in favor of qlog.
-	// It is disabled by default. Use the "quictrace" build tag to enable (e.g. go build -tags quictrace).
-	QuicTracer quictrace.Tracer
-	Tracer     logging.Tracer
+	// DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899).
+	// Packets will then be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
+	DisablePathMTUDiscovery bool
+	// See https://datatracker.ietf.org/doc/draft-ietf-quic-datagram/.
+	// Datagrams will only be available when both peers enable datagram support.
+	EnableDatagrams bool
+	Tracer          logging.Tracer
 
 	// [Psiphon]
 	// ClientHelloSeed is used for TLS Client Hello randomization and replay.
 	ClientHelloSeed *prng.Seed
 }
 
+// ConnectionState records basic details about a QUIC connection
+type ConnectionState struct {
+	TLS               handshake.ConnectionState
+	SupportsDatagrams bool
+}
+
 // A Listener for incoming QUIC connections
 type Listener interface {
 	// Close the server. All active sessions will be closed.

+ 2 - 3
vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/ackhandler.go

@@ -4,19 +4,18 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
 	"github.com/Psiphon-Labs/quic-go/logging"
-	"github.com/Psiphon-Labs/quic-go/quictrace"
 )
 
 // NewAckHandler creates a new SentPacketHandler and a new ReceivedPacketHandler
 func NewAckHandler(
 	initialPacketNumber protocol.PacketNumber,
+	initialMaxDatagramSize protocol.ByteCount,
 	rttStats *utils.RTTStats,
 	pers protocol.Perspective,
-	traceCallback func(quictrace.Event),
 	tracer logging.ConnectionTracer,
 	logger utils.Logger,
 	version protocol.VersionNumber,
 ) (SentPacketHandler, ReceivedPacketHandler) {
-	sph := newSentPacketHandler(initialPacketNumber, rttStats, pers, traceCallback, tracer, logger)
+	sph := newSentPacketHandler(initialPacketNumber, initialMaxDatagramSize, rttStats, pers, tracer, logger)
 	return sph, newReceivedPacketHandler(sph, rttStats, logger, version)
 }

+ 3 - 4
vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/interfaces.go

@@ -5,7 +5,6 @@ import (
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/internal/wire"
-	"github.com/Psiphon-Labs/quic-go/quictrace"
 )
 
 // A Packet is a packet
@@ -17,6 +16,8 @@ type Packet struct {
 	EncryptionLevel protocol.EncryptionLevel
 	SendTime        time.Time
 
+	IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.
+
 	includedInBytesInFlight bool
 	declaredLost            bool
 	skippedPacket           bool
@@ -39,6 +40,7 @@ type SentPacketHandler interface {
 	TimeUntilSend() time.Time
 	// HasPacingBudget says if the pacer allows sending of a (full size) packet at this moment.
 	HasPacingBudget() bool
+	SetMaxDatagramSize(count protocol.ByteCount)
 
 	// only to be called once the handshake is complete
 	QueueProbePacket(protocol.EncryptionLevel) bool /* was a packet queued */
@@ -48,9 +50,6 @@ type SentPacketHandler interface {
 
 	GetLossDetectionTimeout() time.Time
 	OnLossDetectionTimeout() error
-
-	// report some congestion statistics. For tracing only.
-	GetStats() *quictrace.TransportState
 }
 
 type sentPacketTracker interface {

+ 45 - 30
vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/packet_number_generator.go

@@ -1,41 +1,67 @@
 package ackhandler
 
 import (
-	"crypto/rand"
-	"math"
-
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
+	"github.com/Psiphon-Labs/quic-go/internal/utils"
 )
 
-// The packetNumberGenerator generates the packet number for the next packet
+type packetNumberGenerator interface {
+	Peek() protocol.PacketNumber
+	Pop() protocol.PacketNumber
+}
+
+type sequentialPacketNumberGenerator struct {
+	next protocol.PacketNumber
+}
+
+var _ packetNumberGenerator = &sequentialPacketNumberGenerator{}
+
+func newSequentialPacketNumberGenerator(initial protocol.PacketNumber) packetNumberGenerator {
+	return &sequentialPacketNumberGenerator{next: initial}
+}
+
+func (p *sequentialPacketNumberGenerator) Peek() protocol.PacketNumber {
+	return p.next
+}
+
+func (p *sequentialPacketNumberGenerator) Pop() protocol.PacketNumber {
+	next := p.next
+	p.next++
+	return next
+}
+
+// The skippingPacketNumberGenerator generates the packet number for the next packet
 // it randomly skips a packet number every averagePeriod packets (on average).
 // It is guaranteed to never skip two consecutive packet numbers.
-type packetNumberGenerator struct {
-	averagePeriod protocol.PacketNumber
+type skippingPacketNumberGenerator struct {
+	period    protocol.PacketNumber
+	maxPeriod protocol.PacketNumber
 
 	next       protocol.PacketNumber
 	nextToSkip protocol.PacketNumber
+
+	rng utils.Rand
 }
 
-func newPacketNumberGenerator(initial, averagePeriod protocol.PacketNumber) *packetNumberGenerator {
-	g := &packetNumberGenerator{
-		next:          initial,
-		averagePeriod: averagePeriod,
+var _ packetNumberGenerator = &skippingPacketNumberGenerator{}
+
+func newSkippingPacketNumberGenerator(initial, initialPeriod, maxPeriod protocol.PacketNumber) packetNumberGenerator {
+	g := &skippingPacketNumberGenerator{
+		next:      initial,
+		period:    initialPeriod,
+		maxPeriod: maxPeriod,
 	}
 	g.generateNewSkip()
 	return g
 }
 
-func (p *packetNumberGenerator) Peek() protocol.PacketNumber {
+func (p *skippingPacketNumberGenerator) Peek() protocol.PacketNumber {
 	return p.next
 }
 
-func (p *packetNumberGenerator) Pop() protocol.PacketNumber {
+func (p *skippingPacketNumberGenerator) Pop() protocol.PacketNumber {
 	next := p.next
-
-	// generate a new packet number for the next packet
-	p.next++
-
+	p.next++ // generate a new packet number for the next packet
 	if p.next == p.nextToSkip {
 		p.next++
 		p.generateNewSkip()
@@ -43,19 +69,8 @@ func (p *packetNumberGenerator) Pop() protocol.PacketNumber {
 	return next
 }
 
-func (p *packetNumberGenerator) generateNewSkip() {
-	num := p.getRandomNumber()
-	skip := protocol.PacketNumber(num) * (p.averagePeriod - 1) / (math.MaxUint16 / 2)
+func (p *skippingPacketNumberGenerator) generateNewSkip() {
 	// make sure that there are never two consecutive packet numbers that are skipped
-	p.nextToSkip = p.next + 2 + skip
-}
-
-// getRandomNumber() generates a cryptographically secure random number between 0 and MaxUint16 (= 65535)
-// The expectation value is 65535/2
-func (p *packetNumberGenerator) getRandomNumber() uint16 {
-	b := make([]byte, 2)
-	rand.Read(b) // ignore the error here
-
-	num := uint16(b[0])<<8 + uint16(b[1])
-	return num
+	p.nextToSkip = p.next + 2 + protocol.PacketNumber(p.rng.Int31n(int32(2*p.period)))
+	p.period = utils.MinPacketNumber(2*p.period, p.maxPeriod)
 }

+ 1 - 3
vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/received_packet_handler.go

@@ -130,9 +130,7 @@ func (h *receivedPacketHandler) IsPotentiallyDuplicate(pn protocol.PacketNumber,
 			return h.handshakePackets.IsPotentiallyDuplicate(pn)
 		}
 	case protocol.Encryption0RTT, protocol.Encryption1RTT:
-		if h.appDataPackets != nil {
-			return h.appDataPackets.IsPotentiallyDuplicate(pn)
-		}
+		return h.appDataPackets.IsPotentiallyDuplicate(pn)
 	}
 	panic("unexpected encryption level")
 }

+ 4 - 8
vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/received_packet_history.go

@@ -44,23 +44,19 @@ func (h *receivedPacketHistory) addToRanges(p protocol.PacketNumber) bool /* is
 			return false
 		}
 
-		var rangeExtended bool
 		if el.Value.End == p-1 { // extend a range at the end
-			rangeExtended = true
 			el.Value.End = p
-		} else if el.Value.Start == p+1 { // extend a range at the beginning
-			rangeExtended = true
-			el.Value.Start = p
+			return true
 		}
+		if el.Value.Start == p+1 { // extend a range at the beginning
+			el.Value.Start = p
 
-		// if a range was extended (either at the beginning or at the end, maybe it is possible to merge two ranges into one)
-		if rangeExtended {
 			prev := el.Prev()
 			if prev != nil && prev.Value.End+1 == el.Value.Start { // merge two ranges
 				prev.Value.End = el.Value.End
 				h.ranges.Remove(el)
 			}
-			return true // if the two ranges were not merge, we're done here
+			return true
 		}
 
 		// create a new range at the end

+ 112 - 118
vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/sent_packet_handler.go

@@ -11,7 +11,6 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
 	"github.com/Psiphon-Labs/quic-go/internal/wire"
 	"github.com/Psiphon-Labs/quic-go/logging"
-	"github.com/Psiphon-Labs/quic-go/quictrace"
 )
 
 const (
@@ -22,11 +21,13 @@ const (
 	packetThreshold = 3
 	// Before validating the client's address, the server won't send more than 3x bytes than it received.
 	amplificationFactor = 3
+	// We use Retry packets to derive an RTT estimate. Make sure we don't set the RTT to a super low value yet.
+	minRTTAfterRetry = 5 * time.Millisecond
 )
 
 type packetNumberSpace struct {
 	history *sentPacketHistory
-	pns     *packetNumberGenerator
+	pns     packetNumberGenerator
 
 	lossTime                   time.Time
 	lastAckElicitingPacketTime time.Time
@@ -35,10 +36,16 @@ type packetNumberSpace struct {
 	largestSent  protocol.PacketNumber
 }
 
-func newPacketNumberSpace(initialPN protocol.PacketNumber, rttStats *utils.RTTStats) *packetNumberSpace {
+func newPacketNumberSpace(initialPN protocol.PacketNumber, skipPNs bool, rttStats *utils.RTTStats) *packetNumberSpace {
+	var pns packetNumberGenerator
+	if skipPNs {
+		pns = newSkippingPacketNumberGenerator(initialPN, protocol.SkipPacketInitialPeriod, protocol.SkipPacketMaxPeriod)
+	} else {
+		pns = newSequentialPacketNumberGenerator(initialPN)
+	}
 	return &packetNumberSpace{
 		history:      newSentPacketHistory(rttStats),
-		pns:          newPacketNumberGenerator(initialPN, protocol.SkipPacketAveragePeriodLength),
+		pns:          pns,
 		largestSent:  protocol.InvalidPacketNumber,
 		largestAcked: protocol.InvalidPacketNumber,
 	}
@@ -66,6 +73,8 @@ type sentPacketHandler struct {
 	// Only applies to the application-data packet number space.
 	lowestNotConfirmedAcked protocol.PacketNumber
 
+	ackedPackets []*Packet // to avoid allocations in detectAndRemoveAckedPackets
+
 	bytesInFlight protocol.ByteCount
 
 	congestion congestion.SendAlgorithmWithDebugInfos
@@ -83,9 +92,8 @@ type sentPacketHandler struct {
 
 	perspective protocol.Perspective
 
-	traceCallback func(quictrace.Event)
-	tracer        logging.ConnectionTracer
-	logger        utils.Logger
+	tracer logging.ConnectionTracer
+	logger utils.Logger
 }
 
 var (
@@ -94,16 +102,17 @@ var (
 )
 
 func newSentPacketHandler(
-	initialPacketNumber protocol.PacketNumber,
+	initialPN protocol.PacketNumber,
+	initialMaxDatagramSize protocol.ByteCount,
 	rttStats *utils.RTTStats,
 	pers protocol.Perspective,
-	traceCallback func(quictrace.Event),
 	tracer logging.ConnectionTracer,
 	logger utils.Logger,
 ) *sentPacketHandler {
 	congestion := congestion.NewCubicSender(
 		congestion.DefaultClock{},
 		rttStats,
+		initialMaxDatagramSize,
 		true, // use Reno
 		tracer,
 	)
@@ -111,13 +120,12 @@ func newSentPacketHandler(
 	return &sentPacketHandler{
 		peerCompletedAddressValidation: pers == protocol.PerspectiveServer,
 		peerAddressValidated:           pers == protocol.PerspectiveClient,
-		initialPackets:                 newPacketNumberSpace(initialPacketNumber, rttStats),
-		handshakePackets:               newPacketNumberSpace(0, rttStats),
-		appDataPackets:                 newPacketNumberSpace(0, rttStats),
+		initialPackets:                 newPacketNumberSpace(initialPN, false, rttStats),
+		handshakePackets:               newPacketNumberSpace(0, false, rttStats),
+		appDataPackets:                 newPacketNumberSpace(0, true, rttStats),
 		rttStats:                       rttStats,
 		congestion:                     congestion,
 		perspective:                    pers,
-		traceCallback:                  traceCallback,
 		tracer:                         tracer,
 		logger:                         logger,
 	}
@@ -165,15 +173,14 @@ func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
 	case protocol.EncryptionHandshake:
 		h.handshakePackets = nil
 	case protocol.Encryption0RTT:
-		// TODO(#2067): invalidate sent data
+		// This function is only called when 0-RTT is rejected,
+		// and not when the client drops 0-RTT keys when the handshake completes.
+		// When 0-RTT is rejected, all application data sent so far becomes invalid.
+		// Delete the packets from the history and remove them from bytes_in_flight.
 		h.appDataPackets.history.Iterate(func(p *Packet) (bool, error) {
-			if p.skippedPacket {
-				return true, nil
-			}
 			if p.EncryptionLevel != protocol.Encryption0RTT {
 				return false, nil
 			}
-			h.queueFramesForRetransmission(p)
 			h.removeFromBytesInFlight(p)
 			h.appDataPackets.history.Remove(p.PacketNumber)
 			return true, nil
@@ -191,12 +198,17 @@ func (h *sentPacketHandler) dropPackets(encLevel protocol.EncryptionLevel) {
 }
 
 func (h *sentPacketHandler) ReceivedBytes(n protocol.ByteCount) {
+	wasAmplificationLimit := h.isAmplificationLimited()
 	h.bytesReceived += n
+	if wasAmplificationLimit && !h.isAmplificationLimited() {
+		h.setLossDetectionTimer()
+	}
 }
 
-func (h *sentPacketHandler) ReceivedPacket(encLevel protocol.EncryptionLevel) {
-	if h.perspective == protocol.PerspectiveServer && encLevel == protocol.EncryptionHandshake {
+func (h *sentPacketHandler) ReceivedPacket(l protocol.EncryptionLevel) {
+	if h.perspective == protocol.PerspectiveServer && l == protocol.EncryptionHandshake && !h.peerAddressValidated {
 		h.peerAddressValidated = true
+		h.setLossDetectionTimer()
 	}
 }
 
@@ -302,22 +314,12 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
 				h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
 			}
 			h.congestion.MaybeExitSlowStart()
-			if h.tracer != nil {
-				h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
-			}
 		}
 	}
-	lostPackets, err := h.detectLostPackets(rcvTime, encLevel)
-	if err != nil {
+	if err := h.detectLostPackets(rcvTime, encLevel); err != nil {
 		return err
 	}
-	for _, p := range lostPackets {
-		h.congestion.OnPacketLost(p.PacketNumber, p.Length, priorInFlight)
-	}
 	for _, p := range ackedPackets {
-		if p.skippedPacket {
-			return fmt.Errorf("received an ACK for skipped packet number: %d (%s)", p.PacketNumber, encLevel)
-		}
 		if p.includedInBytesInFlight && !p.declaredLost {
 			h.congestion.OnPacketAcked(p.PacketNumber, p.Length, priorInFlight, rcvTime)
 		}
@@ -333,6 +335,10 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
 	}
 	h.numProbesToSend = 0
 
+	if h.tracer != nil {
+		h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
+	}
+
 	pnSpace.history.DeleteOldPackets(rcvTime)
 	h.setLossDetectionTimer()
 	return nil
@@ -345,7 +351,7 @@ func (h *sentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNu
 // Packets are returned in ascending packet number order.
 func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encLevel protocol.EncryptionLevel) ([]*Packet, error) {
 	pnSpace := h.getPacketNumberSpace(encLevel)
-	var ackedPackets []*Packet
+	h.ackedPackets = h.ackedPackets[:0]
 	ackRangeIndex := 0
 	lowestAcked := ack.LowestAcked()
 	largestAcked := ack.LargestAcked()
@@ -367,26 +373,28 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
 				ackRange = ack.AckRanges[len(ack.AckRanges)-1-ackRangeIndex]
 			}
 
-			if p.PacketNumber >= ackRange.Smallest { // packet i contained in ACK range
-				if p.PacketNumber > ackRange.Largest {
-					return false, fmt.Errorf("BUG: ackhandler would have acked wrong packet %d, while evaluating range %d -> %d", p.PacketNumber, ackRange.Smallest, ackRange.Largest)
-				}
-				ackedPackets = append(ackedPackets, p)
+			if p.PacketNumber < ackRange.Smallest { // packet not contained in ACK range
+				return true, nil
+			}
+			if p.PacketNumber > ackRange.Largest {
+				return false, fmt.Errorf("BUG: ackhandler would have acked wrong packet %d, while evaluating range %d -> %d", p.PacketNumber, ackRange.Smallest, ackRange.Largest)
 			}
-		} else {
-			ackedPackets = append(ackedPackets, p)
 		}
+		if p.skippedPacket {
+			return false, fmt.Errorf("received an ACK for skipped packet number: %d (%s)", p.PacketNumber, encLevel)
+		}
+		h.ackedPackets = append(h.ackedPackets, p)
 		return true, nil
 	})
-	if h.logger.Debug() && len(ackedPackets) > 0 {
-		pns := make([]protocol.PacketNumber, len(ackedPackets))
-		for i, p := range ackedPackets {
+	if h.logger.Debug() && len(h.ackedPackets) > 0 {
+		pns := make([]protocol.PacketNumber, len(h.ackedPackets))
+		for i, p := range h.ackedPackets {
 			pns[i] = p.PacketNumber
 		}
 		h.logger.Debugf("\tnewly acked packets (%d): %d", len(pns), pns)
 	}
 
-	for _, p := range ackedPackets {
+	for _, p := range h.ackedPackets {
 		if p.LargestAcked != protocol.InvalidPacketNumber && encLevel == protocol.Encryption1RTT {
 			h.lowestNotConfirmedAcked = utils.MaxPacketNumber(h.lowestNotConfirmedAcked, p.LargestAcked+1)
 		}
@@ -399,9 +407,12 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
 		if err := pnSpace.history.Remove(p.PacketNumber); err != nil {
 			return nil, err
 		}
+		if h.tracer != nil {
+			h.tracer.AcknowledgedPacket(encLevel, p.PacketNumber)
+		}
 	}
 
-	return ackedPackets, err
+	return h.ackedPackets, err
 }
 
 func (h *sentPacketHandler) getLossTimeAndSpace() (time.Time, protocol.EncryptionLevel) {
@@ -481,7 +492,8 @@ func (h *sentPacketHandler) hasOutstandingPackets() bool {
 
 func (h *sentPacketHandler) setLossDetectionTimer() {
 	oldAlarm := h.alarm // only needed in case tracing is enabled
-	if lossTime, encLevel := h.getLossTimeAndSpace(); !lossTime.IsZero() {
+	lossTime, encLevel := h.getLossTimeAndSpace()
+	if !lossTime.IsZero() {
 		// Early retransmit timer or time loss detection.
 		h.alarm = lossTime
 		if h.tracer != nil && h.alarm != oldAlarm {
@@ -490,12 +502,26 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
 		return
 	}
 
+	// Cancel the alarm if amplification limited.
+	if h.isAmplificationLimited() {
+		h.alarm = time.Time{}
+		if !oldAlarm.IsZero() {
+			h.logger.Debugf("Canceling loss detection timer. Amplification limited.")
+			if h.tracer != nil {
+				h.tracer.LossTimerCanceled()
+			}
+		}
+		return
+	}
+
 	// Cancel the alarm if no packets are outstanding
 	if !h.hasOutstandingPackets() && h.peerCompletedAddressValidation {
 		h.alarm = time.Time{}
-		h.logger.Debugf("Canceling loss detection timer. No packets in flight.")
-		if h.tracer != nil && !oldAlarm.IsZero() {
-			h.tracer.LossTimerCanceled()
+		if !oldAlarm.IsZero() {
+			h.logger.Debugf("Canceling loss detection timer. No packets in flight.")
+			if h.tracer != nil {
+				h.tracer.LossTimerCanceled()
+			}
 		}
 		return
 	}
@@ -508,7 +534,7 @@ func (h *sentPacketHandler) setLossDetectionTimer() {
 	}
 }
 
-func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.EncryptionLevel) ([]*Packet, error) {
+func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.EncryptionLevel) error {
 	pnSpace := h.getPacketNumberSpace(encLevel)
 	pnSpace.lossTime = time.Time{}
 
@@ -521,68 +547,51 @@ func (h *sentPacketHandler) detectLostPackets(now time.Time, encLevel protocol.E
 	// Packets sent before this time are deemed lost.
 	lostSendTime := now.Add(-lossDelay)
 
-	var lostPackets []*Packet
-	if err := pnSpace.history.Iterate(func(packet *Packet) (bool, error) {
-		if packet.PacketNumber > pnSpace.largestAcked {
+	priorInFlight := h.bytesInFlight
+	return pnSpace.history.Iterate(func(p *Packet) (bool, error) {
+		if p.PacketNumber > pnSpace.largestAcked {
 			return false, nil
 		}
-		if packet.declaredLost || packet.skippedPacket {
+		if p.declaredLost || p.skippedPacket {
 			return true, nil
 		}
 
-		if packet.SendTime.Before(lostSendTime) {
-			lostPackets = append(lostPackets, packet)
+		var packetLost bool
+		if p.SendTime.Before(lostSendTime) {
+			packetLost = true
+			if h.logger.Debug() {
+				h.logger.Debugf("\tlost packet %d (time threshold)", p.PacketNumber)
+			}
 			if h.tracer != nil {
-				h.tracer.LostPacket(packet.EncryptionLevel, packet.PacketNumber, logging.PacketLossTimeThreshold)
+				h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossTimeThreshold)
+			}
+		} else if pnSpace.largestAcked >= p.PacketNumber+packetThreshold {
+			packetLost = true
+			if h.logger.Debug() {
+				h.logger.Debugf("\tlost packet %d (reordering threshold)", p.PacketNumber)
 			}
-		} else if pnSpace.largestAcked >= packet.PacketNumber+packetThreshold {
-			lostPackets = append(lostPackets, packet)
 			if h.tracer != nil {
-				h.tracer.LostPacket(packet.EncryptionLevel, packet.PacketNumber, logging.PacketLossReorderingThreshold)
+				h.tracer.LostPacket(p.EncryptionLevel, p.PacketNumber, logging.PacketLossReorderingThreshold)
 			}
 		} else if pnSpace.lossTime.IsZero() {
 			// Note: This conditional is only entered once per call
-			lossTime := packet.SendTime.Add(lossDelay)
+			lossTime := p.SendTime.Add(lossDelay)
 			if h.logger.Debug() {
-				h.logger.Debugf("\tsetting loss timer for packet %d (%s) to %s (in %s)", packet.PacketNumber, encLevel, lossDelay, lossTime)
+				h.logger.Debugf("\tsetting loss timer for packet %d (%s) to %s (in %s)", p.PacketNumber, encLevel, lossDelay, lossTime)
 			}
 			pnSpace.lossTime = lossTime
 		}
-		return true, nil
-	}); err != nil {
-		return nil, err
-	}
-
-	if h.logger.Debug() && len(lostPackets) > 0 {
-		pns := make([]protocol.PacketNumber, len(lostPackets))
-		for i, p := range lostPackets {
-			pns[i] = p.PacketNumber
-		}
-		h.logger.Debugf("\tlost packets (%d): %d", len(pns), pns)
-	}
-
-	for _, p := range lostPackets {
-		p.declaredLost = true
-		h.queueFramesForRetransmission(p)
-		// the bytes in flight need to be reduced no matter if this packet will be retransmitted
-		h.removeFromBytesInFlight(p)
-		if h.traceCallback != nil {
-			frames := make([]wire.Frame, 0, len(p.Frames))
-			for _, f := range p.Frames {
-				frames = append(frames, f.Frame)
+		if packetLost {
+			p.declaredLost = true
+			// the bytes in flight need to be reduced no matter if the frames in this packet will be retransmitted
+			h.removeFromBytesInFlight(p)
+			h.queueFramesForRetransmission(p)
+			if !p.IsPathMTUProbePacket {
+				h.congestion.OnPacketLost(p.PacketNumber, p.Length, priorInFlight)
 			}
-			h.traceCallback(quictrace.Event{
-				Time:            now,
-				EventType:       quictrace.PacketLost,
-				EncryptionLevel: p.EncryptionLevel,
-				PacketNumber:    p.PacketNumber,
-				PacketSize:      p.Length,
-				Frames:          frames,
-				TransportState:  h.GetStats(),
-			})
 		}
-	}
-	return lostPackets, nil
+		return true, nil
+	})
 }
 
 func (h *sentPacketHandler) OnLossDetectionTimeout() error {
@@ -609,15 +618,7 @@ func (h *sentPacketHandler) onVerifiedLossDetectionTimeout() error {
 			h.tracer.LossTimerExpired(logging.TimerTypeACK, encLevel)
 		}
 		// Early retransmit or time loss detection
-		priorInFlight := h.bytesInFlight
-		lostPackets, err := h.detectLostPackets(time.Now(), encLevel)
-		if err != nil {
-			return err
-		}
-		for _, p := range lostPackets {
-			h.congestion.OnPacketLost(p.PacketNumber, p.Length, priorInFlight)
-		}
-		return nil
+		return h.detectLostPackets(time.Now(), encLevel)
 	}
 
 	// PTO
@@ -733,6 +734,10 @@ func (h *sentPacketHandler) HasPacingBudget() bool {
 	return h.congestion.HasPacingBudget()
 }
 
+func (h *sentPacketHandler) SetMaxDatagramSize(s protocol.ByteCount) {
+	h.congestion.SetMaxDatagramSize(s)
+}
+
 func (h *sentPacketHandler) isAmplificationLimited() bool {
 	if h.peerAddressValidated {
 		return false
@@ -789,8 +794,9 @@ func (h *sentPacketHandler) ResetForRetry() error {
 	// Only use the Retry to estimate the RTT if we didn't send any retransmission for the Initial.
 	// Otherwise, we don't know which Initial the Retry was sent in response to.
 	if h.ptoCount == 0 {
+		// Don't set the RTT to a value lower than 5ms here.
 		now := time.Now()
-		h.rttStats.UpdateRTT(now.Sub(firstPacketSendTime), 0, now)
+		h.rttStats.UpdateRTT(utils.MaxDuration(minRTTAfterRetry, now.Sub(firstPacketSendTime)), 0, now)
 		if h.logger.Debug() {
 			h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
 		}
@@ -798,8 +804,8 @@ func (h *sentPacketHandler) ResetForRetry() error {
 			h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
 		}
 	}
-	h.initialPackets = newPacketNumberSpace(h.initialPackets.pns.Pop(), h.rttStats)
-	h.appDataPackets = newPacketNumberSpace(h.appDataPackets.pns.Pop(), h.rttStats)
+	h.initialPackets = newPacketNumberSpace(h.initialPackets.pns.Pop(), false, h.rttStats)
+	h.appDataPackets = newPacketNumberSpace(h.appDataPackets.pns.Pop(), true, h.rttStats)
 	oldAlarm := h.alarm
 	h.alarm = time.Time{}
 	if h.tracer != nil {
@@ -818,15 +824,3 @@ func (h *sentPacketHandler) SetHandshakeConfirmed() {
 	// Make sure the timer is armed now, if necessary.
 	h.setLossDetectionTimer()
 }
-
-func (h *sentPacketHandler) GetStats() *quictrace.TransportState {
-	return &quictrace.TransportState{
-		MinRTT:           h.rttStats.MinRTT(),
-		SmoothedRTT:      h.rttStats.SmoothedRTT(),
-		LatestRTT:        h.rttStats.LatestRTT(),
-		BytesInFlight:    h.bytesInFlight,
-		CongestionWindow: h.congestion.GetCongestionWindow(),
-		InSlowStart:      h.congestion.InSlowStart(),
-		InRecovery:       h.congestion.InRecovery(),
-	}
-}

+ 3 - 2
vendor/github.com/Psiphon-Labs/quic-go/internal/ackhandler/sent_packet_history.go

@@ -64,8 +64,9 @@ func (h *sentPacketHistory) Iterate(cb func(*Packet) (cont bool, err error)) err
 // FirstOutStanding returns the first outstanding packet.
 func (h *sentPacketHistory) FirstOutstanding() *Packet {
 	for el := h.packetList.Front(); el != nil; el = el.Next() {
-		if !el.Value.declaredLost && !el.Value.skippedPacket {
-			return &el.Value
+		p := &el.Value
+		if !p.declaredLost && !p.skippedPacket && !p.IsPathMTUProbePacket {
+			return p
 		}
 	}
 	return nil

+ 2 - 0
vendor/github.com/Psiphon-Labs/quic-go/internal/congestion/cubic.go

@@ -21,6 +21,8 @@ const (
 	cubeScale                                    = 40
 	cubeCongestionWindowScale                    = 410
 	cubeFactor                protocol.ByteCount = 1 << cubeScale / cubeCongestionWindowScale / maxDatagramSize
+	// TODO: when re-enabling cubic, make sure to use the actual packet size here
+	maxDatagramSize = protocol.ByteCount(protocol.InitialPacketSizeIPv4)
 )
 
 const defaultNumConnections = 1

+ 69 - 36
vendor/github.com/Psiphon-Labs/quic-go/internal/congestion/cubic_sender.go

@@ -1,6 +1,7 @@
 package congestion
 
 import (
+	"fmt"
 	"time"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
@@ -11,12 +12,11 @@ import (
 const (
 	// maxDatagramSize is the default maximum packet size used in the Linux TCP implementation.
 	// Used in QUIC for congestion window computations in bytes.
-	maxDatagramSize         = protocol.ByteCount(protocol.MaxPacketSizeIPv4)
-	maxBurstBytes           = 3 * maxDatagramSize
-	renoBeta                = 0.7 // Reno backoff factor.
-	maxCongestionWindow     = protocol.MaxCongestionWindowPackets * maxDatagramSize
-	minCongestionWindow     = 2 * maxDatagramSize
-	initialCongestionWindow = 32 * maxDatagramSize
+	initialMaxDatagramSize     = protocol.ByteCount(protocol.InitialPacketSizeIPv4)
+	maxBurstPackets            = 3
+	renoBeta                   = 0.7 // Reno backoff factor.
+	minCongestionWindowPackets = 2
+	initialCongestionWindow    = 32
 )
 
 type cubicSender struct {
@@ -44,12 +44,6 @@ type cubicSender struct {
 	// Congestion window in packets.
 	congestionWindow protocol.ByteCount
 
-	// Minimum congestion window in packets.
-	minCongestionWindow protocol.ByteCount
-
-	// Maximum congestion window.
-	maxCongestionWindow protocol.ByteCount
-
 	// Slow start congestion window in bytes, aka ssthresh.
 	slowStartThreshold protocol.ByteCount
 
@@ -59,6 +53,8 @@ type cubicSender struct {
 	initialCongestionWindow    protocol.ByteCount
 	initialMaxCongestionWindow protocol.ByteCount
 
+	maxDatagramSize protocol.ByteCount
+
 	lastState logging.CongestionState
 	tracer    logging.ConnectionTracer
 }
@@ -69,11 +65,33 @@ var (
 )
 
 // NewCubicSender makes a new cubic sender
-func NewCubicSender(clock Clock, rttStats *utils.RTTStats, reno bool, tracer logging.ConnectionTracer) *cubicSender {
-	return newCubicSender(clock, rttStats, reno, initialCongestionWindow, maxCongestionWindow, tracer)
+func NewCubicSender(
+	clock Clock,
+	rttStats *utils.RTTStats,
+	initialMaxDatagramSize protocol.ByteCount,
+	reno bool,
+	tracer logging.ConnectionTracer,
+) *cubicSender {
+	return newCubicSender(
+		clock,
+		rttStats,
+		reno,
+		initialMaxDatagramSize,
+		initialCongestionWindow*initialMaxDatagramSize,
+		protocol.MaxCongestionWindowPackets*initialMaxDatagramSize,
+		tracer,
+	)
 }
 
-func newCubicSender(clock Clock, rttStats *utils.RTTStats, reno bool, initialCongestionWindow, initialMaxCongestionWindow protocol.ByteCount, tracer logging.ConnectionTracer) *cubicSender {
+func newCubicSender(
+	clock Clock,
+	rttStats *utils.RTTStats,
+	reno bool,
+	initialMaxDatagramSize,
+	initialCongestionWindow,
+	initialMaxCongestionWindow protocol.ByteCount,
+	tracer logging.ConnectionTracer,
+) *cubicSender {
 	c := &cubicSender{
 		rttStats:                   rttStats,
 		largestSentPacketNumber:    protocol.InvalidPacketNumber,
@@ -82,13 +100,12 @@ func newCubicSender(clock Clock, rttStats *utils.RTTStats, reno bool, initialCon
 		initialCongestionWindow:    initialCongestionWindow,
 		initialMaxCongestionWindow: initialMaxCongestionWindow,
 		congestionWindow:           initialCongestionWindow,
-		minCongestionWindow:        minCongestionWindow,
-		slowStartThreshold:         initialMaxCongestionWindow,
-		maxCongestionWindow:        initialMaxCongestionWindow,
+		slowStartThreshold:         protocol.MaxByteCount,
 		cubic:                      NewCubic(clock),
 		clock:                      clock,
 		reno:                       reno,
 		tracer:                     tracer,
+		maxDatagramSize:            initialMaxDatagramSize,
 	}
 	c.pacer = newPacer(c.BandwidthEstimate)
 	if c.tracer != nil {
@@ -104,12 +121,20 @@ func (c *cubicSender) TimeUntilSend(_ protocol.ByteCount) time.Time {
 }
 
 func (c *cubicSender) HasPacingBudget() bool {
-	return c.pacer.Budget(c.clock.Now()) >= maxDatagramSize
+	return c.pacer.Budget(c.clock.Now()) >= c.maxDatagramSize
+}
+
+func (c *cubicSender) maxCongestionWindow() protocol.ByteCount {
+	return c.maxDatagramSize * protocol.MaxCongestionWindowPackets
+}
+
+func (c *cubicSender) minCongestionWindow() protocol.ByteCount {
+	return c.maxDatagramSize * minCongestionWindowPackets
 }
 
 func (c *cubicSender) OnPacketSent(
 	sentTime time.Time,
-	bytesInFlight protocol.ByteCount,
+	_ protocol.ByteCount,
 	packetNumber protocol.PacketNumber,
 	bytes protocol.ByteCount,
 	isRetransmittable bool,
@@ -139,7 +164,8 @@ func (c *cubicSender) GetCongestionWindow() protocol.ByteCount {
 }
 
 func (c *cubicSender) MaybeExitSlowStart() {
-	if c.InSlowStart() && c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/maxDatagramSize) {
+	if c.InSlowStart() &&
+		c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/c.maxDatagramSize) {
 		// exit slow start
 		c.slowStartThreshold = c.congestionWindow
 		c.maybeTraceStateChange(logging.CongestionStateCongestionAvoidance)
@@ -162,11 +188,7 @@ func (c *cubicSender) OnPacketAcked(
 	}
 }
 
-func (c *cubicSender) OnPacketLost(
-	packetNumber protocol.PacketNumber,
-	lostBytes protocol.ByteCount,
-	priorInFlight protocol.ByteCount,
-) {
+func (c *cubicSender) OnPacketLost(packetNumber protocol.PacketNumber, lostBytes, priorInFlight protocol.ByteCount) {
 	// TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets
 	// already sent should be treated as a single loss event, since it's expected.
 	if packetNumber <= c.largestSentAtLastCutback {
@@ -180,8 +202,8 @@ func (c *cubicSender) OnPacketLost(
 	} else {
 		c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow)
 	}
-	if c.congestionWindow < c.minCongestionWindow {
-		c.congestionWindow = c.minCongestionWindow
+	if minCwnd := c.minCongestionWindow(); c.congestionWindow < minCwnd {
+		c.congestionWindow = minCwnd
 	}
 	c.slowStartThreshold = c.congestionWindow
 	c.largestSentAtLastCutback = c.largestSentPacketNumber
@@ -205,12 +227,12 @@ func (c *cubicSender) maybeIncreaseCwnd(
 		c.maybeTraceStateChange(logging.CongestionStateApplicationLimited)
 		return
 	}
-	if c.congestionWindow >= c.maxCongestionWindow {
+	if c.congestionWindow >= c.maxCongestionWindow() {
 		return
 	}
 	if c.InSlowStart() {
 		// TCP slow start, exponential growth, increase by one for each ACK.
-		c.congestionWindow += maxDatagramSize
+		c.congestionWindow += c.maxDatagramSize
 		c.maybeTraceStateChange(logging.CongestionStateSlowStart)
 		return
 	}
@@ -219,12 +241,12 @@ func (c *cubicSender) maybeIncreaseCwnd(
 	if c.reno {
 		// Classic Reno congestion avoidance.
 		c.numAckedPackets++
-		if c.numAckedPackets >= uint64(c.congestionWindow/maxDatagramSize) {
-			c.congestionWindow += maxDatagramSize
+		if c.numAckedPackets >= uint64(c.congestionWindow/c.maxDatagramSize) {
+			c.congestionWindow += c.maxDatagramSize
 			c.numAckedPackets = 0
 		}
 	} else {
-		c.congestionWindow = utils.MinByteCount(c.maxCongestionWindow, c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime))
+		c.congestionWindow = utils.MinByteCount(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime))
 	}
 }
 
@@ -235,7 +257,7 @@ func (c *cubicSender) isCwndLimited(bytesInFlight protocol.ByteCount) bool {
 	}
 	availableBytes := congestionWindow - bytesInFlight
 	slowStartLimited := c.InSlowStart() && bytesInFlight > congestionWindow/2
-	return slowStartLimited || availableBytes <= maxBurstBytes
+	return slowStartLimited || availableBytes <= maxBurstPackets*c.maxDatagramSize
 }
 
 // BandwidthEstimate returns the current bandwidth estimate
@@ -257,7 +279,7 @@ func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) {
 	c.hybridSlowStart.Restart()
 	c.cubic.Reset()
 	c.slowStartThreshold = c.congestionWindow / 2
-	c.congestionWindow = c.minCongestionWindow
+	c.congestionWindow = c.minCongestionWindow()
 }
 
 // OnConnectionMigration is called when the connection is migrated (?)
@@ -271,7 +293,6 @@ func (c *cubicSender) OnConnectionMigration() {
 	c.numAckedPackets = 0
 	c.congestionWindow = c.initialCongestionWindow
 	c.slowStartThreshold = c.initialMaxCongestionWindow
-	c.maxCongestionWindow = c.initialMaxCongestionWindow
 }
 
 func (c *cubicSender) maybeTraceStateChange(new logging.CongestionState) {
@@ -281,3 +302,15 @@ func (c *cubicSender) maybeTraceStateChange(new logging.CongestionState) {
 	c.tracer.UpdatedCongestionState(new)
 	c.lastState = new
 }
+
+func (c *cubicSender) SetMaxDatagramSize(s protocol.ByteCount) {
+	if s < c.maxDatagramSize {
+		panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", c.maxDatagramSize, s))
+	}
+	cwndIsMinCwnd := c.congestionWindow == c.minCongestionWindow()
+	c.maxDatagramSize = s
+	if cwndIsMinCwnd {
+		c.congestionWindow = c.minCongestionWindow()
+	}
+	c.pacer.SetMaxDatagramSize(s)
+}

+ 1 - 0
vendor/github.com/Psiphon-Labs/quic-go/internal/congestion/interface.go

@@ -16,6 +16,7 @@ type SendAlgorithm interface {
 	OnPacketAcked(number protocol.PacketNumber, ackedBytes protocol.ByteCount, priorInFlight protocol.ByteCount, eventTime time.Time)
 	OnPacketLost(number protocol.PacketNumber, lostBytes protocol.ByteCount, priorInFlight protocol.ByteCount)
 	OnRetransmissionTimeout(packetsRetransmitted bool)
+	SetMaxDatagramSize(protocol.ByteCount)
 }
 
 // A SendAlgorithmWithDebugInfos is a SendAlgorithm that exposes some debug infos

+ 22 - 13
vendor/github.com/Psiphon-Labs/quic-go/internal/congestion/pacer.go

@@ -8,25 +8,29 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
 )
 
-const maxBurstSize = 10 * maxDatagramSize
+const maxBurstSizePackets = 10
 
 // The pacer implements a token bucket pacing algorithm.
 type pacer struct {
 	budgetAtLastSent     protocol.ByteCount
+	maxDatagramSize      protocol.ByteCount
 	lastSentTime         time.Time
 	getAdjustedBandwidth func() uint64 // in bytes/s
 }
 
 func newPacer(getBandwidth func() Bandwidth) *pacer {
-	p := &pacer{getAdjustedBandwidth: func() uint64 {
-		// Bandwidth is in bits/s. We need the value in bytes/s.
-		bw := uint64(getBandwidth() / BytesPerSecond)
-		// Use a slightly higher value than the actual measured bandwidth.
-		// RTT variations then won't result in under-utilization of the congestion window.
-		// Ultimately, this will  result in sending packets as acknowledgments are received rather than when timers fire,
-		// provided the congestion window is fully utilized and acknowledgments arrive at regular intervals.
-		return bw * 5 / 4
-	}}
+	p := &pacer{
+		maxDatagramSize: initialMaxDatagramSize,
+		getAdjustedBandwidth: func() uint64 {
+			// Bandwidth is in bits/s. We need the value in bytes/s.
+			bw := uint64(getBandwidth() / BytesPerSecond)
+			// Use a slightly higher value than the actual measured bandwidth.
+			// RTT variations then won't result in under-utilization of the congestion window.
+			// Ultimately, this will  result in sending packets as acknowledgments are received rather than when timers fire,
+			// provided the congestion window is fully utilized and acknowledgments arrive at regular intervals.
+			return bw * 5 / 4
+		},
+	}
 	p.budgetAtLastSent = p.maxBurstSize()
 	return p
 }
@@ -52,17 +56,22 @@ func (p *pacer) Budget(now time.Time) protocol.ByteCount {
 func (p *pacer) maxBurstSize() protocol.ByteCount {
 	return utils.MaxByteCount(
 		protocol.ByteCount(uint64((protocol.MinPacingDelay+protocol.TimerGranularity).Nanoseconds())*p.getAdjustedBandwidth())/1e9,
-		maxBurstSize,
+		maxBurstSizePackets*p.maxDatagramSize,
 	)
 }
 
 // TimeUntilSend returns when the next packet should be sent.
+// It returns the zero value of time.Time if a packet can be sent immediately.
 func (p *pacer) TimeUntilSend() time.Time {
-	if p.budgetAtLastSent >= maxDatagramSize {
+	if p.budgetAtLastSent >= p.maxDatagramSize {
 		return time.Time{}
 	}
 	return p.lastSentTime.Add(utils.MaxDuration(
 		protocol.MinPacingDelay,
-		time.Duration(math.Ceil(float64(maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.getAdjustedBandwidth())))*time.Nanosecond,
+		time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.getAdjustedBandwidth())))*time.Nanosecond,
 	))
 }
+
+func (p *pacer) SetMaxDatagramSize(s protocol.ByteCount) {
+	p.maxDatagramSize = s
+}

+ 1 - 2
vendor/github.com/Psiphon-Labs/quic-go/internal/flowcontrol/base_flow_controller.go

@@ -45,8 +45,7 @@ func (c *baseFlowController) AddBytesSent(n protocol.ByteCount) {
 	c.bytesSent += n
 }
 
-// UpdateSendWindow should be called after receiving a WindowUpdateFrame
-// it returns true if the window was actually updated
+// UpdateSendWindow is be called after receiving a MAX_{STREAM_}DATA frame.
 func (c *baseFlowController) UpdateSendWindow(offset protocol.ByteCount) {
 	if offset > c.sendWindow {
 		c.sendWindow = offset

+ 16 - 0
vendor/github.com/Psiphon-Labs/quic-go/internal/flowcontrol/connection_flow_controller.go

@@ -1,6 +1,7 @@
 package flowcontrol
 
 import (
+	"errors"
 	"fmt"
 	"time"
 
@@ -86,3 +87,18 @@ func (c *connectionFlowController) EnsureMinimumWindowSize(inc protocol.ByteCoun
 	}
 	c.mutex.Unlock()
 }
+
+// The flow controller is reset when 0-RTT is rejected.
+// All stream data is invalidated, it's if we had never opened a stream and never sent any data.
+// At that point, we only have sent stream data, but we didn't have the keys to open 1-RTT keys yet.
+func (c *connectionFlowController) Reset() error {
+	c.mutex.Lock()
+	defer c.mutex.Unlock()
+
+	if c.bytesRead > 0 || c.highestReceived > 0 || !c.epochStartTime.IsZero() {
+		return errors.New("flow controller reset after reading data")
+	}
+	c.bytesSent = 0
+	c.lastBlockedAt = 0
+	return nil
+}

+ 1 - 0
vendor/github.com/Psiphon-Labs/quic-go/internal/flowcontrol/interface.go

@@ -29,6 +29,7 @@ type StreamFlowController interface {
 // The ConnectionFlowController is the flow controller for the connection.
 type ConnectionFlowController interface {
 	flowController
+	Reset() error
 }
 
 type connectionFlowControllerI interface {

+ 21 - 8
vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/crypto_setup.go

@@ -17,6 +17,7 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
 	"github.com/Psiphon-Labs/quic-go/internal/wire"
 	"github.com/Psiphon-Labs/quic-go/logging"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // TLS unexpected_message alert
@@ -93,6 +94,8 @@ type cryptoSetup struct {
 	extraConf *qtls.ExtraConfig
 	conn      *qtls.Conn
 
+	version protocol.VersionNumber
+
 	messageChan               chan []byte
 	isReadingHandshakeMessage chan struct{}
 	readFirstHandshakeMessage bool
@@ -187,6 +190,7 @@ func NewCryptoSetupClient(
 		tracer,
 		logger,
 		protocol.PerspectiveClient,
+		version,
 
 		// [Psiphon]
 		clientHelloPRNG,
@@ -227,6 +231,7 @@ func NewCryptoSetupServer(
 		tracer,
 		logger,
 		protocol.PerspectiveServer,
+		version,
 
 		// [Psiphon]
 		nil,
@@ -247,14 +252,15 @@ func newCryptoSetup(
 	tracer logging.ConnectionTracer,
 	logger utils.Logger,
 	perspective protocol.Perspective,
+	version protocol.VersionNumber,
 	clientHelloPRNG *prng.PRNG,
 ) (*cryptoSetup, <-chan *wire.TransportParameters /* ClientHello written. Receive nil for non-0-RTT */) {
-	initialSealer, initialOpener := NewInitialAEAD(connID, perspective)
+	initialSealer, initialOpener := NewInitialAEAD(connID, perspective, version)
 	if tracer != nil {
 		tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveClient)
 		tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveServer)
 	}
-	extHandler := newExtensionHandler(tp.Marshal(perspective, clientHelloPRNG), perspective)
+	extHandler := newExtensionHandler(tp.Marshal(perspective, clientHelloPRNG), perspective, version)
 	cs := &cryptoSetup{
 		tlsConf:                   tlsConf,
 		initialStream:             initialStream,
@@ -277,6 +283,7 @@ func newCryptoSetup(
 		messageChan:               make(chan []byte, 100),
 		isReadingHandshakeMessage: make(chan struct{}),
 		closeChan:                 make(chan struct{}),
+		version:                   version,
 	}
 	var maxEarlyData uint32
 	if enable0RTT {
@@ -298,7 +305,7 @@ func newCryptoSetup(
 }
 
 func (h *cryptoSetup) ChangeConnectionID(id protocol.ConnectionID) {
-	initialSealer, initialOpener := NewInitialAEAD(id, h.perspective)
+	initialSealer, initialOpener := NewInitialAEAD(id, h.perspective, h.version)
 	h.initialSealer = initialSealer
 	h.initialOpener = initialOpener
 	if h.tracer != nil {
@@ -428,8 +435,8 @@ func (h *cryptoSetup) handleTransportParameters(data []byte) {
 // must be called after receiving the transport parameters
 func (h *cryptoSetup) marshalDataForSessionState() []byte {
 	buf := &bytes.Buffer{}
-	utils.WriteVarInt(buf, clientSessionStateRevision)
-	utils.WriteVarInt(buf, uint64(h.rttStats.SmoothedRTT().Microseconds()))
+	quicvarint.Write(buf, clientSessionStateRevision)
+	quicvarint.Write(buf, uint64(h.rttStats.SmoothedRTT().Microseconds()))
 	h.peerParams.MarshalForSessionTicket(buf)
 	return buf.Bytes()
 }
@@ -445,14 +452,14 @@ func (h *cryptoSetup) handleDataFromSessionState(data []byte) {
 
 func (h *cryptoSetup) handleDataFromSessionStateImpl(data []byte) (*wire.TransportParameters, error) {
 	r := bytes.NewReader(data)
-	ver, err := utils.ReadVarInt(r)
+	ver, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
 	if ver != clientSessionStateRevision {
 		return nil, fmt.Errorf("mismatching version. Got %d, expected %d", ver, clientSessionStateRevision)
 	}
-	rtt, err := utils.ReadVarInt(r)
+	rtt, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -482,7 +489,7 @@ func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
 func (h *cryptoSetup) accept0RTT(sessionTicketData []byte) bool {
 	var t sessionTicket
 	if err := t.Unmarshal(sessionTicketData); err != nil {
-		h.logger.Debugf("Unmarshaling transport parameters from session ticket failed: %s", err.Error())
+		h.logger.Debugf("Unmarshalling transport parameters from session ticket failed: %s", err.Error())
 		return false
 	}
 	valid := h.ourParams.ValidFor0RTT(t.Parameters)
@@ -633,6 +640,9 @@ func (h *cryptoSetup) SetWriteKey(encLevel qtls.EncryptionLevel, suite *qtls.Cip
 		if h.zeroRTTSealer != nil {
 			h.zeroRTTSealer = nil
 			h.logger.Debugf("Dropping 0-RTT keys.")
+			if h.tracer != nil {
+				h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
+			}
 		}
 	default:
 		panic("unexpected write encryption level")
@@ -794,6 +804,9 @@ func (h *cryptoSetup) Get1RTTOpener() (ShortHeaderOpener, error) {
 	if h.zeroRTTOpener != nil && time.Since(h.handshakeCompleteTime) > 3*h.rttStats.PTO(true) {
 		h.zeroRTTOpener = nil
 		h.logger.Debugf("Dropping 0-RTT keys.")
+		if h.tracer != nil {
+			h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
+		}
 	}
 
 	if !h.has1RTTOpener {

+ 15 - 5
vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/initial_aead.go

@@ -8,7 +8,17 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/qtls"
 )
 
-var quicVersion1Salt = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}
+var (
+	quicSaltOld     = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}
+	quicSaltDraft34 = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}
+)
+
+func getSalt(v protocol.VersionNumber) []byte {
+	if v == protocol.VersionDraft34 {
+		return quicSaltDraft34
+	}
+	return quicSaltOld
+}
 
 var initialSuite = &qtls.CipherSuiteTLS13{
 	ID:     tls.TLS_AES_128_GCM_SHA256,
@@ -18,8 +28,8 @@ var initialSuite = &qtls.CipherSuiteTLS13{
 }
 
 // NewInitialAEAD creates a new AEAD for Initial encryption / decryption.
-func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective) (LongHeaderSealer, LongHeaderOpener) {
-	clientSecret, serverSecret := computeSecrets(connID)
+func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective, v protocol.VersionNumber) (LongHeaderSealer, LongHeaderOpener) {
+	clientSecret, serverSecret := computeSecrets(connID, v)
 	var mySecret, otherSecret []byte
 	if pers == protocol.PerspectiveClient {
 		mySecret = clientSecret
@@ -38,8 +48,8 @@ func NewInitialAEAD(connID protocol.ConnectionID, pers protocol.Perspective) (Lo
 		newLongHeaderOpener(decrypter, newAESHeaderProtector(initialSuite, otherSecret, true))
 }
 
-func computeSecrets(connID protocol.ConnectionID) (clientSecret, serverSecret []byte) {
-	initialSecret := qtls.HkdfExtract(crypto.SHA256, connID, quicVersion1Salt)
+func computeSecrets(connID protocol.ConnectionID, v protocol.VersionNumber) (clientSecret, serverSecret []byte) {
+	initialSecret := qtls.HkdfExtract(crypto.SHA256, connID, getSalt(v))
 	clientSecret = hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size())
 	serverSecret = hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "server in", crypto.SHA256.Size())
 	return

+ 20 - 8
vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/retry.go

@@ -10,11 +10,17 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 )
 
-var retryAEAD cipher.AEAD
+var (
+	oldRetryAEAD cipher.AEAD // used for QUIC draft versions up to 34
+	retryAEAD    cipher.AEAD // used for QUIC draft-34
+)
 
 func init() {
-	key := [16]byte{0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, 0xe1}
+	oldRetryAEAD = initAEAD([16]byte{0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a, 0x6c, 0xb9, 0x6b, 0xe1})
+	retryAEAD = initAEAD([16]byte{0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a, 0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e})
+}
 
+func initAEAD(key [16]byte) cipher.AEAD {
 	aes, err := aes.NewCipher(key[:])
 	if err != nil {
 		panic(err)
@@ -23,24 +29,30 @@ func init() {
 	if err != nil {
 		panic(err)
 	}
-	retryAEAD = aead
+	return aead
 }
 
 var (
-	retryBuf   bytes.Buffer
-	retryMutex sync.Mutex
-	retryNonce = [12]byte{0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c}
+	retryBuf      bytes.Buffer
+	retryMutex    sync.Mutex
+	oldRetryNonce = [12]byte{0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c}
+	retryNonce    = [12]byte{0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2, 0x23, 0x98, 0x25, 0xbb}
 )
 
 // GetRetryIntegrityTag calculates the integrity tag on a Retry packet
-func GetRetryIntegrityTag(retry []byte, origDestConnID protocol.ConnectionID) *[16]byte {
+func GetRetryIntegrityTag(retry []byte, origDestConnID protocol.ConnectionID, version protocol.VersionNumber) *[16]byte {
 	retryMutex.Lock()
 	retryBuf.WriteByte(uint8(origDestConnID.Len()))
 	retryBuf.Write(origDestConnID.Bytes())
 	retryBuf.Write(retry)
 
 	var tag [16]byte
-	sealed := retryAEAD.Seal(tag[:0], retryNonce[:], nil, retryBuf.Bytes())
+	var sealed []byte
+	if version != protocol.VersionDraft34 {
+		sealed = oldRetryAEAD.Seal(tag[:0], oldRetryNonce[:], nil, retryBuf.Bytes())
+	} else {
+		sealed = retryAEAD.Seal(tag[:0], retryNonce[:], nil, retryBuf.Bytes())
+	}
 	if len(sealed) != 16 {
 		panic(fmt.Sprintf("unexpected Retry integrity tag length: %d", len(sealed)))
 	}

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

@@ -6,8 +6,8 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
 	"github.com/Psiphon-Labs/quic-go/internal/wire"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 const sessionTicketRevision = 2
@@ -19,22 +19,22 @@ type sessionTicket struct {
 
 func (t *sessionTicket) Marshal() []byte {
 	b := &bytes.Buffer{}
-	utils.WriteVarInt(b, sessionTicketRevision)
-	utils.WriteVarInt(b, uint64(t.RTT.Microseconds()))
+	quicvarint.Write(b, sessionTicketRevision)
+	quicvarint.Write(b, uint64(t.RTT.Microseconds()))
 	t.Parameters.MarshalForSessionTicket(b)
 	return b.Bytes()
 }
 
 func (t *sessionTicket) Unmarshal(b []byte) error {
 	r := bytes.NewReader(b)
-	rev, err := utils.ReadVarInt(r)
+	rev, err := quicvarint.Read(r)
 	if err != nil {
 		return errors.New("failed to read session ticket revision")
 	}
 	if rev != sessionTicketRevision {
 		return fmt.Errorf("unknown session ticket revision: %d", rev)
 	}
-	rtt, err := utils.ReadVarInt(r)
+	rtt, err := quicvarint.Read(r)
 	if err != nil {
 		return errors.New("failed to read RTT")
 	}

+ 17 - 7
vendor/github.com/Psiphon-Labs/quic-go/internal/handshake/tls_extension_handler.go

@@ -5,23 +5,33 @@ import (
 	"github.com/Psiphon-Labs/quic-go/internal/qtls"
 )
 
-const quicTLSExtensionType = 0xffa5
+const (
+	quicTLSExtensionTypeOldDrafts = 0xffa5
+	quicTLSExtensionType          = 0x39
+)
 
 type extensionHandler struct {
 	ourParams  []byte
 	paramsChan chan []byte
 
+	extensionType uint16
+
 	perspective protocol.Perspective
 }
 
 var _ tlsExtensionHandler = &extensionHandler{}
 
 // newExtensionHandler creates a new extension handler
-func newExtensionHandler(params []byte, pers protocol.Perspective) tlsExtensionHandler {
+func newExtensionHandler(params []byte, pers protocol.Perspective, v protocol.VersionNumber) tlsExtensionHandler {
+	et := uint16(quicTLSExtensionType)
+	if v != protocol.VersionDraft34 {
+		et = quicTLSExtensionTypeOldDrafts
+	}
 	return &extensionHandler{
-		ourParams:   params,
-		paramsChan:  make(chan []byte),
-		perspective: pers,
+		ourParams:     params,
+		paramsChan:    make(chan []byte),
+		perspective:   pers,
+		extensionType: et,
 	}
 }
 
@@ -31,7 +41,7 @@ func (h *extensionHandler) GetExtensions(msgType uint8) []qtls.Extension {
 		return nil
 	}
 	return []qtls.Extension{{
-		Type: quicTLSExtensionType,
+		Type: h.extensionType,
 		Data: h.ourParams,
 	}}
 }
@@ -44,7 +54,7 @@ func (h *extensionHandler) ReceivedExtensions(msgType uint8, exts []qtls.Extensi
 
 	var data []byte
 	for _, ext := range exts {
-		if ext.Type == quicTLSExtensionType {
+		if ext.Type == h.extensionType {
 			data = ext.Data
 			break
 		}

+ 4 - 0
vendor/github.com/Psiphon-Labs/quic-go/internal/logutils/frame.go

@@ -23,6 +23,10 @@ func ConvertFrame(frame wire.Frame) logging.Frame {
 			Length:   f.DataLen(),
 			Fin:      f.Fin,
 		}
+	case *wire.DatagramFrame:
+		return &logging.DatagramFrame{
+			Length: logging.ByteCount(len(f.Data)),
+		}
 	default:
 		return logging.Frame(frame)
 	}

+ 3 - 3
vendor/github.com/Psiphon-Labs/quic-go/internal/protocol/connection_id.go

@@ -10,7 +10,7 @@ import (
 // A ConnectionID in QUIC
 type ConnectionID []byte
 
-const maxConnectionIDLen = 18
+const maxConnectionIDLen = 20
 
 // GenerateConnectionID generates a connection ID using cryptographic random
 func GenerateConnectionID(len int) (ConnectionID, error) {
@@ -22,7 +22,7 @@ func GenerateConnectionID(len int) (ConnectionID, error) {
 }
 
 // GenerateConnectionIDForInitial generates a connection ID for the Initial packet.
-// It uses a length randomly chosen between 8 and 18 bytes.
+// It uses a length randomly chosen between 8 and 20 bytes.
 func GenerateConnectionIDForInitial() (ConnectionID, error) {
 	r := make([]byte, 1)
 	if _, err := rand.Read(r); err != nil {
@@ -65,5 +65,5 @@ func (c ConnectionID) String() string {
 	if c.Len() == 0 {
 		return "(empty)"
 	}
-	return fmt.Sprintf("%#x", c.Bytes())
+	return fmt.Sprintf("%x", c.Bytes())
 }

+ 32 - 16
vendor/github.com/Psiphon-Labs/quic-go/internal/protocol/params.go

@@ -5,33 +5,33 @@ import "time"
 // DesiredReceiveBufferSize is the kernel UDP receive buffer size that we'd like to use.
 const DesiredReceiveBufferSize = (1 << 20) * 2 // 2 MB
 
-// MaxPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
-const MaxPacketSizeIPv4 = 1252
+// InitialPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
+const InitialPacketSizeIPv4 = 1252
 
-// MaxPacketSizeIPv6 is the maximum packet size that we use for sending IPv6 packets.
-const MaxPacketSizeIPv6 = 1232
+// InitialPacketSizeIPv6 is the maximum packet size that we use for sending IPv6 packets.
+const InitialPacketSizeIPv6 = 1232
 
 // MaxCongestionWindowPackets is the maximum congestion window in packet.
 const MaxCongestionWindowPackets = 10000
 
 // MaxUndecryptablePackets limits the number of undecryptable packets that are queued in the session.
-const MaxUndecryptablePackets = 33
+const MaxUndecryptablePackets = 32
 
 // ConnectionFlowControlMultiplier determines how much larger the connection flow control windows needs to be relative to any stream's flow control window
 // This is the value that Chromium is using
 const ConnectionFlowControlMultiplier = 1.5
 
-// InitialMaxStreamData is the stream-level flow control window for receiving data
-const InitialMaxStreamData = (1 << 10) * 512 // 512 kb
+// DefaultInitialMaxStreamData is the default initial stream-level flow control window for receiving data
+const DefaultInitialMaxStreamData = (1 << 10) * 512 // 512 kb
 
-// InitialMaxData is the connection-level flow control window for receiving data
-const InitialMaxData = ConnectionFlowControlMultiplier * InitialMaxStreamData
+// DefaultInitialMaxData is the connection-level flow control window for receiving data
+const DefaultInitialMaxData = ConnectionFlowControlMultiplier * DefaultInitialMaxStreamData
 
-// DefaultMaxReceiveStreamFlowControlWindow is the default maximum stream-level flow control window for receiving data, for the server
+// DefaultMaxReceiveStreamFlowControlWindow is the default maximum stream-level flow control window for receiving data
 const DefaultMaxReceiveStreamFlowControlWindow = 6 * (1 << 20) // 6 MB
 
-// DefaultMaxReceiveConnectionFlowControlWindow is the default connection-level flow control window for receiving data, for the server
-const DefaultMaxReceiveConnectionFlowControlWindow = 15 * (1 << 20) // 12 MB
+// DefaultMaxReceiveConnectionFlowControlWindow is the default connection-level flow control window for receiving data
+const DefaultMaxReceiveConnectionFlowControlWindow = 15 * (1 << 20) // 15 MB
 
 // WindowUpdateThreshold is the fraction of the receive window that has to be consumed before an higher offset is advertised to the client
 const WindowUpdateThreshold = 0.25
@@ -48,8 +48,12 @@ const MaxServerUnprocessedPackets = 1024
 // MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed.
 const MaxSessionUnprocessedPackets = 256
 
-// SkipPacketAveragePeriodLength is the average period length in which one packet number is skipped to prevent an Optimistic ACK attack
-const SkipPacketAveragePeriodLength PacketNumber = 500
+// SkipPacketInitialPeriod is the initial period length used for packet number skipping to prevent an Optimistic ACK attack.
+// Every time a packet number is skipped, the period is doubled, up to SkipPacketMaxPeriod.
+const SkipPacketInitialPeriod PacketNumber = 256
+
+// SkipPacketMaxPeriod is the maximum period length used for packet number skipping.
+const SkipPacketMaxPeriod PacketNumber = 128 * 1024
 
 // MaxAcceptQueueSize is the maximum number of sessions that the server queues for accepting.
 // If the queue is full, new connection attempts will be rejected.
@@ -98,6 +102,9 @@ const MinRemoteIdleTimeout = 5 * time.Second
 // DefaultIdleTimeout is the default idle timeout
 const DefaultIdleTimeout = 30 * time.Second
 
+// DefaultHandshakeIdleTimeout is the default idle timeout used before handshake completion.
+const DefaultHandshakeIdleTimeout = 5 * time.Second
+
 // DefaultHandshakeTimeout is the default timeout for a connection until the crypto handshake succeeds.
 const DefaultHandshakeTimeout = 10 * time.Second
 
@@ -125,10 +132,19 @@ const MaxPostHandshakeCryptoFrameSize = 1000
 // but must ensure that a maximum size ACK frame fits into one packet.
 const MaxAckFrameSize ByteCount = 1000
 
+// MaxDatagramFrameSize is the maximum size of a DATAGRAM frame as defined in
+// https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
+// The size is chosen such that a DATAGRAM frame fits into a QUIC packet.
+const MaxDatagramFrameSize ByteCount = 1220
+
+// DatagramRcvQueueLen is the length of the receive queue for DATAGRAM frames.
+// See https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
+const DatagramRcvQueueLen = 128
+
 // MaxNumAckRanges is the maximum number of ACK ranges that we send in an ACK frame.
 // It also serves as a limit for the packet history.
 // If at any point we keep track of more ranges, old ranges are discarded.
-const MaxNumAckRanges = 500
+const MaxNumAckRanges = 32
 
 // MinPacingDelay is the minimum duration that is used for packet pacing
 // If the packet packing frequency is higher, multiple packets might be sent at once.
@@ -176,4 +192,4 @@ const Max0RTTQueues = 32
 // When a new session is created, all buffered packets are passed to the session immediately.
 // To avoid blocking, this value has to be smaller than MaxSessionUnprocessedPackets.
 // To avoid packets being dropped as undecryptable by the session, this value has to be smaller than MaxUndecryptablePackets.
-const Max0RTTQueueLen = 32
+const Max0RTTQueueLen = 31

+ 6 - 3
vendor/github.com/Psiphon-Labs/quic-go/internal/protocol/protocol.go

@@ -44,22 +44,25 @@ const (
 )
 
 // A ByteCount in QUIC
-type ByteCount uint64
+type ByteCount int64
 
 // MaxByteCount is the maximum value of a ByteCount
 const MaxByteCount = ByteCount(1<<62 - 1)
 
+// InvalidByteCount is an invalid byte count
+const InvalidByteCount ByteCount = -1
+
 // An ApplicationErrorCode is an application-defined error code.
 type ApplicationErrorCode uint64
 
 // A StatelessResetToken is a stateless reset token.
 type StatelessResetToken [16]byte
 
-// MaxReceivePacketSize maximum packet size of any QUIC packet, based on
+// MaxPacketBufferSize maximum packet size of any QUIC packet, based on
 // ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header,
 // UDP adds an additional 8 bytes.  This is a total overhead of 48 bytes.
 // Ethernet's max packet size is 1500 bytes,  1500 - 48 = 1452.
-const MaxReceivePacketSize ByteCount = 1452
+const MaxPacketBufferSize ByteCount = 1452
 
 // MinInitialPacketSize is the minimum size an Initial packet is required to have.
 const MinInitialPacketSize = 1200

+ 4 - 1
vendor/github.com/Psiphon-Labs/quic-go/internal/protocol/version.go

@@ -23,11 +23,12 @@ const (
 	VersionUnknown  VersionNumber = math.MaxUint32
 	VersionDraft29  VersionNumber = 0xff00001d
 	VersionDraft32  VersionNumber = 0xff000020
+	VersionDraft34  VersionNumber = 0xff000022 // If everything goes according to plan at the IETF, this will one day be QUIC v1.
 )
 
 // SupportedVersions lists the versions that the server supports
 // must be in sorted descending order
-var SupportedVersions = []VersionNumber{VersionDraft32, VersionDraft29}
+var SupportedVersions = []VersionNumber{VersionDraft29, VersionDraft34, VersionDraft32}
 
 // IsValidVersion says if the version is known to quic-go
 func IsValidVersion(v VersionNumber) bool {
@@ -50,6 +51,8 @@ func (vn VersionNumber) String() string {
 		return "draft-29"
 	case VersionDraft32:
 		return "draft-32"
+	case VersionDraft34:
+		return "draft-34"
 	default:
 		if vn.isGQUIC() {
 			return fmt.Sprintf("gQUIC %d", vn.toGQUICVersion())

+ 15 - 5
vendor/github.com/Psiphon-Labs/quic-go/internal/qerr/quic_error.go

@@ -5,6 +5,11 @@ import (
 	"net"
 )
 
+var (
+	ErrIdleTimeout      = newTimeoutError("No recent network activity")
+	ErrHandshakeTimeout = newTimeoutError("Handshake did not complete in time")
+)
+
 // A QuicError consists of an error code plus a error reason
 type QuicError struct {
 	ErrorCode          ErrorCode
@@ -33,8 +38,8 @@ func NewErrorWithFrameType(errorCode ErrorCode, frameType uint64, errorMessage s
 	}
 }
 
-// NewTimeoutError creates a new QuicError instance for a timeout error
-func NewTimeoutError(errorMessage string) *QuicError {
+// newTimeoutError creates a new QuicError instance for a timeout error
+func newTimeoutError(errorMessage string) *QuicError {
 	return &QuicError{
 		ErrorMessage: errorMessage,
 		isTimeout:    true,
@@ -65,9 +70,14 @@ func (e *QuicError) Error() string {
 		}
 		return fmt.Sprintf("Application error %#x: %s", uint64(e.ErrorCode), e.ErrorMessage)
 	}
-	str := e.ErrorCode.String()
-	if e.FrameType != 0 {
-		str += fmt.Sprintf(" (frame type: %#x)", e.FrameType)
+	var str string
+	if e.isTimeout {
+		str = "Timeout"
+	} else {
+		str = e.ErrorCode.String()
+		if e.FrameType != 0 {
+			str += fmt.Sprintf(" (frame type: %#x)", e.FrameType)
+		}
 	}
 	msg := e.ErrorMessage
 	if len(msg) == 0 {

+ 0 - 190
vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go114.go

@@ -1,190 +0,0 @@
-// +build !go1.15
-
-package qtls
-
-import (
-	"crypto"
-	"crypto/cipher"
-	"crypto/tls"
-	"net"
-	"unsafe"
-
-	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
-	"github.com/Psiphon-Labs/qtls"
-)
-
-type (
-	// Alert is a TLS alert
-	Alert = qtls.Alert
-	// A Certificate is qtls.Certificate.
-	Certificate = qtls.Certificate
-	// CertificateRequestInfo contains inforamtion about a certificate request.
-	CertificateRequestInfo = qtls.CertificateRequestInfo
-	// A CipherSuiteTLS13 is a cipher suite for TLS 1.3
-	CipherSuiteTLS13 = qtls.CipherSuiteTLS13
-	// ClientHelloInfo contains information about a ClientHello.
-	ClientHelloInfo = qtls.ClientHelloInfo
-	// ClientSessionCache is a cache used for session resumption.
-	ClientSessionCache = qtls.ClientSessionCache
-	// ClientSessionState is a state needed for session resumption.
-	ClientSessionState = qtls.ClientSessionState
-	// A Config is a qtls.Config.
-	Config = qtls.Config
-	// A Conn is a qtls.Conn.
-	Conn = qtls.Conn
-	// ConnectionState contains information about the state of the connection.
-	ConnectionState = qtls.ConnectionState
-	// EncryptionLevel is the encryption level of a message.
-	EncryptionLevel = qtls.EncryptionLevel
-	// Extension is a TLS extension
-	Extension = qtls.Extension
-	// RecordLayer is a qtls RecordLayer.
-	RecordLayer = qtls.RecordLayer
-)
-
-type ExtraConfig struct {
-	// GetExtensions, if not nil, is called before a message that allows
-	// sending of extensions is sent.
-	// Currently only implemented for the ClientHello message (for the client)
-	// and for the EncryptedExtensions message (for the server).
-	// Only valid for TLS 1.3.
-	GetExtensions func(handshakeMessageType uint8) []Extension
-
-	// ReceivedExtensions, if not nil, is called when a message that allows the
-	// inclusion of extensions is received.
-	// It is called with an empty slice of extensions, if the message didn't
-	// contain any extensions.
-	// Currently only implemented for the ClientHello message (sent by the
-	// client) and for the EncryptedExtensions message (sent by the server).
-	// Only valid for TLS 1.3.
-	ReceivedExtensions func(handshakeMessageType uint8, exts []Extension)
-
-	// AlternativeRecordLayer is used by QUIC
-	AlternativeRecordLayer RecordLayer
-
-	// Enforce the selection of a supported application protocol.
-	// Only works for TLS 1.3.
-	// If enabled, client and server have to agree on an application protocol.
-	// Otherwise, connection establishment fails.
-	EnforceNextProtoSelection bool
-
-	// If MaxEarlyData is greater than 0, the client will be allowed to send early
-	// data when resuming a session.
-	// Requires the AlternativeRecordLayer to be set.
-	//
-	// It has no meaning on the client.
-	MaxEarlyData uint32
-
-	// The Accept0RTT callback is called when the client offers 0-RTT.
-	// The server then has to decide if it wants to accept or reject 0-RTT.
-	// It is only used for servers.
-	Accept0RTT func(appData []byte) bool
-
-	// 0RTTRejected is called when the server rejectes 0-RTT.
-	// It is only used for clients.
-	Rejected0RTT func()
-
-	// If set, the client will export the 0-RTT key when resuming a session that
-	// allows sending of early data.
-	// Requires the AlternativeRecordLayer to be set.
-	//
-	// It has no meaning to the server.
-	Enable0RTT bool
-
-	// Is called when the client saves a session ticket to the session ticket.
-	// This gives the application the opportunity to save some data along with the ticket,
-	// which can be restored when the session ticket is used.
-	GetAppDataForSessionState func() []byte
-
-	// Is called when the client uses a session ticket.
-	// Restores the application data that was saved earlier on GetAppDataForSessionTicket.
-	SetAppDataFromSessionState func([]byte)
-
-	// [Psiphon]
-	// ClientHelloPRNG is used for Client Hello randomization and replay.
-	ClientHelloPRNG *prng.PRNG
-}
-
-const (
-	// EncryptionHandshake is the Handshake encryption level
-	EncryptionHandshake = qtls.EncryptionHandshake
-	// Encryption0RTT is the 0-RTT encryption level
-	Encryption0RTT = qtls.Encryption0RTT
-	// EncryptionApplication is the application data encryption level
-	EncryptionApplication = qtls.EncryptionApplication
-)
-
-// CipherSuiteName gets the name of a cipher suite.
-func CipherSuiteName(id uint16) string {
-	return qtls.CipherSuiteName(id)
-}
-
-// HkdfExtract generates a pseudorandom key for use with Expand from an input secret and an optional independent salt.
-func HkdfExtract(hash crypto.Hash, newSecret, currentSecret []byte) []byte {
-	return qtls.HkdfExtract(hash, newSecret, currentSecret)
-}
-
-// HkdfExpandLabel HKDF expands a label
-func HkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte {
-	return qtls.HkdfExpandLabel(hash, secret, hashValue, label, L)
-}
-
-// AEADAESGCMTLS13 creates a new AES-GCM AEAD for TLS 1.3
-func AEADAESGCMTLS13(key, fixedNonce []byte) cipher.AEAD {
-	return qtls.AEADAESGCMTLS13(key, fixedNonce)
-}
-
-// Client returns a new TLS client side connection.
-func Client(conn net.Conn, config *tls.Config, extraConfig *ExtraConfig) *Conn {
-	return qtls.Client(conn, tlsConfigToQtlsConfig(config, extraConfig))
-}
-
-// Server returns a new TLS server side connection.
-func Server(conn net.Conn, config *tls.Config, extraConfig *ExtraConfig) *Conn {
-	return qtls.Server(conn, tlsConfigToQtlsConfig(config, extraConfig))
-}
-
-func GetConnectionState(conn *Conn) ConnectionState {
-	return conn.ConnectionState()
-}
-
-// ToTLSConnectionState extracts the tls.ConnectionState
-// Warning: Calling ExportKeyingMaterial won't work.
-func ToTLSConnectionState(cs ConnectionState) tls.ConnectionState {
-	return tls.ConnectionState{
-		Version:                     cs.Version,
-		HandshakeComplete:           cs.HandshakeComplete,
-		DidResume:                   cs.DidResume,
-		CipherSuite:                 cs.CipherSuite,
-		NegotiatedProtocol:          cs.NegotiatedProtocol,
-		NegotiatedProtocolIsMutual:  cs.NegotiatedProtocolIsMutual,
-		ServerName:                  cs.ServerName,
-		PeerCertificates:            cs.PeerCertificates,
-		VerifiedChains:              cs.VerifiedChains,
-		SignedCertificateTimestamps: cs.SignedCertificateTimestamps,
-		OCSPResponse:                cs.OCSPResponse,
-		TLSUnique:                   cs.TLSUnique,
-	}
-}
-
-type cipherSuiteTLS13 struct {
-	ID     uint16
-	KeyLen int
-	AEAD   func(key, fixedNonce []byte) cipher.AEAD
-	Hash   crypto.Hash
-}
-
-//go:linkname cipherSuiteTLS13ByID github.com/Psiphon-Labs/qtls.cipherSuiteTLS13ByID
-func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13
-
-// CipherSuiteTLS13ByID gets a TLS 1.3 cipher suite.
-func CipherSuiteTLS13ByID(id uint16) *CipherSuiteTLS13 {
-	val := cipherSuiteTLS13ByID(id)
-	cs := (*cipherSuiteTLS13)(unsafe.Pointer(val))
-	return &qtls.CipherSuiteTLS13{
-		ID:     cs.ID,
-		KeyLen: cs.KeyLen,
-		AEAD:   cs.AEAD,
-		Hash:   cs.Hash,
-	}
-}

+ 1 - 0
vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go115.go

@@ -1,4 +1,5 @@
 // +build go1.15
+// +build !go1.16
 
 package qtls
 

+ 114 - 0
vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/go116.go

@@ -0,0 +1,114 @@
+// +build go1.16
+
+package qtls
+
+import (
+	"crypto"
+	"crypto/cipher"
+	"crypto/tls"
+	"net"
+	"unsafe"
+
+	qtls "github.com/Psiphon-Labs/qtls-go1-16"
+)
+
+type (
+	// Alert is a TLS alert
+	Alert = qtls.Alert
+	// A Certificate is qtls.Certificate.
+	Certificate = qtls.Certificate
+	// CertificateRequestInfo contains inforamtion about a certificate request.
+	CertificateRequestInfo = qtls.CertificateRequestInfo
+	// A CipherSuiteTLS13 is a cipher suite for TLS 1.3
+	CipherSuiteTLS13 = qtls.CipherSuiteTLS13
+	// ClientHelloInfo contains information about a ClientHello.
+	ClientHelloInfo = qtls.ClientHelloInfo
+	// ClientSessionCache is a cache used for session resumption.
+	ClientSessionCache = qtls.ClientSessionCache
+	// ClientSessionState is a state needed for session resumption.
+	ClientSessionState = qtls.ClientSessionState
+	// A Config is a qtls.Config.
+	Config = qtls.Config
+	// A Conn is a qtls.Conn.
+	Conn = qtls.Conn
+	// ConnectionState contains information about the state of the connection.
+	ConnectionState = qtls.ConnectionStateWith0RTT
+	// EncryptionLevel is the encryption level of a message.
+	EncryptionLevel = qtls.EncryptionLevel
+	// Extension is a TLS extension
+	Extension = qtls.Extension
+	// ExtraConfig is the qtls.ExtraConfig
+	ExtraConfig = qtls.ExtraConfig
+	// RecordLayer is a qtls RecordLayer.
+	RecordLayer = qtls.RecordLayer
+)
+
+const (
+	// EncryptionHandshake is the Handshake encryption level
+	EncryptionHandshake = qtls.EncryptionHandshake
+	// Encryption0RTT is the 0-RTT encryption level
+	Encryption0RTT = qtls.Encryption0RTT
+	// EncryptionApplication is the application data encryption level
+	EncryptionApplication = qtls.EncryptionApplication
+)
+
+// CipherSuiteName gets the name of a cipher suite.
+func CipherSuiteName(id uint16) string {
+	return qtls.CipherSuiteName(id)
+}
+
+// HkdfExtract generates a pseudorandom key for use with Expand from an input secret and an optional independent salt.
+func HkdfExtract(hash crypto.Hash, newSecret, currentSecret []byte) []byte {
+	return qtls.HkdfExtract(hash, newSecret, currentSecret)
+}
+
+// HkdfExpandLabel HKDF expands a label
+func HkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte {
+	return qtls.HkdfExpandLabel(hash, secret, hashValue, label, L)
+}
+
+// AEADAESGCMTLS13 creates a new AES-GCM AEAD for TLS 1.3
+func AEADAESGCMTLS13(key, fixedNonce []byte) cipher.AEAD {
+	return qtls.AEADAESGCMTLS13(key, fixedNonce)
+}
+
+// Client returns a new TLS client side connection.
+func Client(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
+	return qtls.Client(conn, config, extraConfig)
+}
+
+// Server returns a new TLS server side connection.
+func Server(conn net.Conn, config *Config, extraConfig *ExtraConfig) *Conn {
+	return qtls.Server(conn, config, extraConfig)
+}
+
+func GetConnectionState(conn *Conn) ConnectionState {
+	return conn.ConnectionStateWith0RTT()
+}
+
+// ToTLSConnectionState extracts the tls.ConnectionState
+func ToTLSConnectionState(cs ConnectionState) tls.ConnectionState {
+	return cs.ConnectionState
+}
+
+type cipherSuiteTLS13 struct {
+	ID     uint16
+	KeyLen int
+	AEAD   func(key, fixedNonce []byte) cipher.AEAD
+	Hash   crypto.Hash
+}
+
+//go:linkname cipherSuiteTLS13ByID github.com/Psiphon-Labs/qtls-go1-16.cipherSuiteTLS13ByID
+func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13
+
+// CipherSuiteTLS13ByID gets a TLS 1.3 cipher suite.
+func CipherSuiteTLS13ByID(id uint16) *CipherSuiteTLS13 {
+	val := cipherSuiteTLS13ByID(id)
+	cs := (*cipherSuiteTLS13)(unsafe.Pointer(val))
+	return &qtls.CipherSuiteTLS13{
+		ID:     cs.ID,
+		KeyLen: cs.KeyLen,
+		AEAD:   cs.AEAD,
+		Hash:   cs.Hash,
+	}
+}

+ 0 - 219
vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/qtls.go

@@ -1,219 +0,0 @@
-// +build !go1.15
-
-package qtls
-
-// This package uses unsafe to convert between:
-// * Certificate and tls.Certificate
-// * CertificateRequestInfo and tls.CertificateRequestInfo
-// * ClientHelloInfo and tls.ClientHelloInfo
-// * ConnectionState and tls.ConnectionState
-// * ClientSessionState and tls.ClientSessionState
-// We check in init() that this conversion actually is safe.
-
-import (
-	"crypto/tls"
-	"net"
-	"unsafe"
-)
-
-func init() {
-	if !structsEqual(&tls.Certificate{}, &Certificate{}) {
-		panic("Certificate not compatible with tls.Certificate")
-	}
-	if !structsEqual(&tls.CertificateRequestInfo{}, &CertificateRequestInfo{}) {
-		panic("CertificateRequestInfo not compatible with tls.CertificateRequestInfo")
-	}
-	if !structsEqual(&tls.ClientSessionState{}, &ClientSessionState{}) {
-		panic("ClientSessionState not compatible with tls.ClientSessionState")
-	}
-	if !structsEqual(&tls.ClientHelloInfo{}, &clientHelloInfo{}) {
-		panic("clientHelloInfo not compatible with tls.ClientHelloInfo")
-	}
-	if !structsEqual(&ClientHelloInfo{}, &qtlsClientHelloInfo{}) {
-		panic("qtlsClientHelloInfo not compatible with ClientHelloInfo")
-	}
-}
-
-func tlsConfigToQtlsConfig(c *tls.Config, ec *ExtraConfig) *Config {
-	if c == nil {
-		c = &tls.Config{}
-	}
-	if ec == nil {
-		ec = &ExtraConfig{}
-	}
-	// Clone the config first. This executes the tls.Config.serverInit().
-	// This sets the SessionTicketKey, if the user didn't supply one.
-	c = c.Clone()
-	// QUIC requires TLS 1.3 or newer
-	minVersion := c.MinVersion
-	if minVersion < tls.VersionTLS13 {
-		minVersion = tls.VersionTLS13
-	}
-	maxVersion := c.MaxVersion
-	if maxVersion < tls.VersionTLS13 {
-		maxVersion = tls.VersionTLS13
-	}
-	var getConfigForClient func(ch *ClientHelloInfo) (*Config, error)
-	if c.GetConfigForClient != nil {
-		getConfigForClient = func(ch *ClientHelloInfo) (*Config, error) {
-			tlsConf, err := c.GetConfigForClient(toTLSClientHelloInfo(ch))
-			if err != nil {
-				return nil, err
-			}
-			if tlsConf == nil {
-				return nil, nil
-			}
-			return tlsConfigToQtlsConfig(tlsConf, ec), nil
-		}
-	}
-	var getCertificate func(ch *ClientHelloInfo) (*Certificate, error)
-	if c.GetCertificate != nil {
-		getCertificate = func(ch *ClientHelloInfo) (*Certificate, error) {
-			cert, err := c.GetCertificate(toTLSClientHelloInfo(ch))
-			if err != nil {
-				return nil, err
-			}
-			if cert == nil {
-				return nil, nil
-			}
-			return (*Certificate)(cert), nil
-		}
-	}
-	var csc ClientSessionCache
-	if c.ClientSessionCache != nil {
-		csc = &clientSessionCache{c.ClientSessionCache}
-	}
-	conf := &Config{
-		Rand:         c.Rand,
-		Time:         c.Time,
-		Certificates: *(*[]Certificate)(unsafe.Pointer(&c.Certificates)),
-		//nolint:staticcheck // NameToCertificate is deprecated, but we still need to copy it if the user sets it.
-		NameToCertificate:         *(*map[string]*Certificate)(unsafe.Pointer(&c.NameToCertificate)),
-		GetCertificate:            getCertificate,
-		GetClientCertificate:      *(*func(*CertificateRequestInfo) (*Certificate, error))(unsafe.Pointer(&c.GetClientCertificate)),
-		GetConfigForClient:        getConfigForClient,
-		VerifyPeerCertificate:     c.VerifyPeerCertificate,
-		RootCAs:                   c.RootCAs,
-		NextProtos:                c.NextProtos,
-		EnforceNextProtoSelection: true,
-		ServerName:                c.ServerName,
-		ClientAuth:                c.ClientAuth,
-		ClientCAs:                 c.ClientCAs,
-		InsecureSkipVerify:        c.InsecureSkipVerify,
-		CipherSuites:              c.CipherSuites,
-		PreferServerCipherSuites:  c.PreferServerCipherSuites,
-		SessionTicketsDisabled:    c.SessionTicketsDisabled,
-		//nolint:staticcheck // SessionTicketKey is deprecated, but we still need to copy it if the user sets it.
-		SessionTicketKey:            c.SessionTicketKey,
-		ClientSessionCache:          csc,
-		MinVersion:                  minVersion,
-		MaxVersion:                  maxVersion,
-		CurvePreferences:            c.CurvePreferences,
-		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
-		// no need to copy Renegotiation, it's not supported by TLS 1.3
-		KeyLogWriter:               c.KeyLogWriter,
-		AlternativeRecordLayer:     ec.AlternativeRecordLayer,
-		GetExtensions:              ec.GetExtensions,
-		ReceivedExtensions:         ec.ReceivedExtensions,
-		Accept0RTT:                 ec.Accept0RTT,
-		Rejected0RTT:               ec.Rejected0RTT,
-		GetAppDataForSessionState:  ec.GetAppDataForSessionState,
-		SetAppDataFromSessionState: ec.SetAppDataFromSessionState,
-		Enable0RTT:                 ec.Enable0RTT,
-		MaxEarlyData:               ec.MaxEarlyData,
-
-		// [Psiphon]
-		ClientHelloPRNG: ec.ClientHelloPRNG,
-	}
-	return conf
-}
-
-type clientSessionCache struct {
-	tls.ClientSessionCache
-}
-
-var _ ClientSessionCache = &clientSessionCache{}
-
-func (c *clientSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
-	sess, ok := c.ClientSessionCache.Get(sessionKey)
-	if sess == nil {
-		return nil, ok
-	}
-	// ClientSessionState is identical to the tls.ClientSessionState.
-	// In order to allow users of quic-go to use a tls.Config,
-	// we need this workaround to use the ClientSessionCache.
-	// In unsafe.go we check that the two structs are actually identical.
-	return (*ClientSessionState)(unsafe.Pointer(sess)), ok
-}
-
-func (c *clientSessionCache) Put(sessionKey string, cs *ClientSessionState) {
-	if cs == nil {
-		c.ClientSessionCache.Put(sessionKey, nil)
-		return
-	}
-	// ClientSessionState is identical to the tls.ClientSessionState.
-	// In order to allow users of quic-go to use a tls.Config,
-	// we need this workaround to use the ClientSessionCache.
-	// In unsafe.go we check that the two structs are actually identical.
-	c.ClientSessionCache.Put(sessionKey, (*tls.ClientSessionState)(unsafe.Pointer(cs)))
-}
-
-type clientHelloInfo struct {
-	CipherSuites      []uint16
-	ServerName        string
-	SupportedCurves   []tls.CurveID
-	SupportedPoints   []uint8
-	SignatureSchemes  []tls.SignatureScheme
-	SupportedProtos   []string
-	SupportedVersions []uint16
-	Conn              net.Conn
-
-	config *tls.Config
-}
-
-type qtlsClientHelloInfo struct {
-	CipherSuites      []uint16
-	ServerName        string
-	SupportedCurves   []tls.CurveID
-	SupportedPoints   []uint8
-	SignatureSchemes  []tls.SignatureScheme
-	SupportedProtos   []string
-	SupportedVersions []uint16
-	Conn              net.Conn
-
-	config *Config
-}
-
-func toTLSClientHelloInfo(chi *ClientHelloInfo) *tls.ClientHelloInfo {
-	if chi == nil {
-		return nil
-	}
-	qtlsCHI := (*qtlsClientHelloInfo)(unsafe.Pointer(chi))
-	var config *tls.Config
-	if qtlsCHI.config != nil {
-		config = qtlsConfigToTLSConfig(qtlsCHI.config)
-	}
-	return (*tls.ClientHelloInfo)(unsafe.Pointer(&clientHelloInfo{
-		CipherSuites:      chi.CipherSuites,
-		ServerName:        chi.ServerName,
-		SupportedCurves:   chi.SupportedCurves,
-		SupportedPoints:   chi.SupportedPoints,
-		SignatureSchemes:  chi.SignatureSchemes,
-		SupportedProtos:   chi.SupportedProtos,
-		SupportedVersions: chi.SupportedVersions,
-		Conn:              chi.Conn,
-		config:            config,
-	}))
-}
-
-// qtlsConfigToTLSConfig is used to transform a Config to a tls.Config.
-// It is used to create the tls.Config in the ClientHelloInfo.
-// It doesn't copy all values, but only those used by ClientHelloInfo.SupportsCertificate.
-func qtlsConfigToTLSConfig(config *Config) *tls.Config {
-	return &tls.Config{
-		MinVersion:       config.MinVersion,
-		MaxVersion:       config.MaxVersion,
-		CipherSuites:     config.CipherSuites,
-		CurvePreferences: config.CurvePreferences,
-	}
-}

+ 0 - 21
vendor/github.com/Psiphon-Labs/quic-go/internal/qtls/structs_equal.go

@@ -1,21 +0,0 @@
-// +build !go1.15
-
-package qtls
-
-import "reflect"
-
-func structsEqual(a, b interface{}) bool {
-	sa := reflect.ValueOf(a).Elem()
-	sb := reflect.ValueOf(b).Elem()
-	if sa.NumField() != sb.NumField() {
-		return false
-	}
-	for i := 0; i < sa.NumField(); i++ {
-		fa := sa.Type().Field(i)
-		fb := sb.Type().Field(i)
-		if !reflect.DeepEqual(fa.Index, fb.Index) || fa.Name != fb.Name || fa.Anonymous != fb.Anonymous || fa.Offset != fb.Offset || !reflect.DeepEqual(fa.Type, fb.Type) {
-			return false
-		}
-	}
-	return true
-}

+ 29 - 0
vendor/github.com/Psiphon-Labs/quic-go/internal/utils/rand.go

@@ -0,0 +1,29 @@
+package utils
+
+import (
+	"crypto/rand"
+	"encoding/binary"
+)
+
+// Rand is a wrapper around crypto/rand that adds some convenience functions known from math/rand.
+type Rand struct {
+	buf [4]byte
+}
+
+func (r *Rand) Int31() int32 {
+	rand.Read(r.buf[:])
+	return int32(binary.BigEndian.Uint32(r.buf[:]) & ^uint32(1<<31))
+}
+
+// copied from the standard library math/rand implementation of Int63n
+func (r *Rand) Int31n(n int32) int32 {
+	if n&(n-1) == 0 { // n is power of two, can mask
+		return r.Int31() & (n - 1)
+	}
+	max := int32((1 << 31) - 1 - (1<<31)%uint32(n))
+	v := r.Int31()
+	for v > max {
+		v = r.Int31()
+	}
+	return v % n
+}

+ 27 - 26
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/ack_frame.go

@@ -8,6 +8,7 @@ import (
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 var errInvalidAckRanges = errors.New("AckFrame: ACK frame contains invalid ACK ranges")
@@ -30,12 +31,12 @@ func parseAckFrame(r *bytes.Reader, ackDelayExponent uint8, _ protocol.VersionNu
 
 	frame := &AckFrame{}
 
-	la, err := utils.ReadVarInt(r)
+	la, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
 	largestAcked := protocol.PacketNumber(la)
-	delay, err := utils.ReadVarInt(r)
+	delay, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -47,13 +48,13 @@ func parseAckFrame(r *bytes.Reader, ackDelayExponent uint8, _ protocol.VersionNu
 	}
 	frame.DelayTime = delayTime
 
-	numBlocks, err := utils.ReadVarInt(r)
+	numBlocks, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
 
 	// read the first ACK range
-	ab, err := utils.ReadVarInt(r)
+	ab, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -66,7 +67,7 @@ func parseAckFrame(r *bytes.Reader, ackDelayExponent uint8, _ protocol.VersionNu
 	// read all the other ACK ranges
 	frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largestAcked})
 	for i := uint64(0); i < numBlocks; i++ {
-		g, err := utils.ReadVarInt(r)
+		g, err := quicvarint.Read(r)
 		if err != nil {
 			return nil, err
 		}
@@ -76,7 +77,7 @@ func parseAckFrame(r *bytes.Reader, ackDelayExponent uint8, _ protocol.VersionNu
 		}
 		largest := smallest - gap - 2
 
-		ab, err := utils.ReadVarInt(r)
+		ab, err := quicvarint.Read(r)
 		if err != nil {
 			return nil, err
 		}
@@ -96,7 +97,7 @@ func parseAckFrame(r *bytes.Reader, ackDelayExponent uint8, _ protocol.VersionNu
 	// parse (and skip) the ECN section
 	if ecn {
 		for i := 0; i < 3; i++ {
-			if _, err := utils.ReadVarInt(r); err != nil {
+			if _, err := quicvarint.Read(r); err != nil {
 				return nil, err
 			}
 		}
@@ -113,27 +114,27 @@ func (f *AckFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
 	} else {
 		b.WriteByte(0x2)
 	}
-	utils.WriteVarInt(b, uint64(f.LargestAcked()))
-	utils.WriteVarInt(b, encodeAckDelay(f.DelayTime))
+	quicvarint.Write(b, uint64(f.LargestAcked()))
+	quicvarint.Write(b, encodeAckDelay(f.DelayTime))
 
 	numRanges := f.numEncodableAckRanges()
-	utils.WriteVarInt(b, uint64(numRanges-1))
+	quicvarint.Write(b, uint64(numRanges-1))
 
 	// write the first range
 	_, firstRange := f.encodeAckRange(0)
-	utils.WriteVarInt(b, firstRange)
+	quicvarint.Write(b, firstRange)
 
 	// write all the other range
 	for i := 1; i < numRanges; i++ {
 		gap, len := f.encodeAckRange(i)
-		utils.WriteVarInt(b, gap)
-		utils.WriteVarInt(b, len)
+		quicvarint.Write(b, gap)
+		quicvarint.Write(b, len)
 	}
 
 	if hasECN {
-		utils.WriteVarInt(b, f.ECT0)
-		utils.WriteVarInt(b, f.ECT1)
-		utils.WriteVarInt(b, f.ECNCE)
+		quicvarint.Write(b, f.ECT0)
+		quicvarint.Write(b, f.ECT1)
+		quicvarint.Write(b, f.ECNCE)
 	}
 	return nil
 }
@@ -143,21 +144,21 @@ func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
 	largestAcked := f.AckRanges[0].Largest
 	numRanges := f.numEncodableAckRanges()
 
-	length := 1 + utils.VarIntLen(uint64(largestAcked)) + utils.VarIntLen(encodeAckDelay(f.DelayTime))
+	length := 1 + quicvarint.Len(uint64(largestAcked)) + quicvarint.Len(encodeAckDelay(f.DelayTime))
 
-	length += utils.VarIntLen(uint64(numRanges - 1))
+	length += quicvarint.Len(uint64(numRanges - 1))
 	lowestInFirstRange := f.AckRanges[0].Smallest
-	length += utils.VarIntLen(uint64(largestAcked - lowestInFirstRange))
+	length += quicvarint.Len(uint64(largestAcked - lowestInFirstRange))
 
 	for i := 1; i < numRanges; i++ {
 		gap, len := f.encodeAckRange(i)
-		length += utils.VarIntLen(gap)
-		length += utils.VarIntLen(len)
+		length += quicvarint.Len(gap)
+		length += quicvarint.Len(len)
 	}
 	if f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0 {
-		length += utils.VarIntLen(f.ECT0)
-		length += utils.VarIntLen(f.ECT1)
-		length += utils.VarIntLen(f.ECNCE)
+		length += quicvarint.Len(f.ECT0)
+		length += quicvarint.Len(f.ECT1)
+		length += quicvarint.Len(f.ECNCE)
 	}
 	return length
 }
@@ -165,11 +166,11 @@ func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
 // gets the number of ACK ranges that can be encoded
 // such that the resulting frame is smaller than the maximum ACK frame size
 func (f *AckFrame) numEncodableAckRanges() int {
-	length := 1 + utils.VarIntLen(uint64(f.LargestAcked())) + utils.VarIntLen(encodeAckDelay(f.DelayTime))
+	length := 1 + quicvarint.Len(uint64(f.LargestAcked())) + quicvarint.Len(encodeAckDelay(f.DelayTime))
 	length += 2 // assume that the number of ranges will consume 2 bytes
 	for i := 1; i < len(f.AckRanges); i++ {
 		gap, len := f.encodeAckRange(i)
-		rangeLen := utils.VarIntLen(gap) + utils.VarIntLen(len)
+		rangeLen := quicvarint.Len(gap) + quicvarint.Len(len)
 		if length+rangeLen > protocol.MaxAckFrameSize {
 			// Writing range i would exceed the MaxAckFrameSize.
 			// So encode one range less than that.

+ 9 - 9
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/connection_close_frame.go

@@ -6,7 +6,7 @@ import (
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/internal/qerr"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A ConnectionCloseFrame is a CONNECTION_CLOSE frame
@@ -24,21 +24,21 @@ func parseConnectionCloseFrame(r *bytes.Reader, _ protocol.VersionNumber) (*Conn
 	}
 
 	f := &ConnectionCloseFrame{IsApplicationError: typeByte == 0x1d}
-	ec, err := utils.ReadVarInt(r)
+	ec, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
 	f.ErrorCode = qerr.ErrorCode(ec)
 	// read the Frame Type, if this is not an application error
 	if !f.IsApplicationError {
-		ft, err := utils.ReadVarInt(r)
+		ft, err := quicvarint.Read(r)
 		if err != nil {
 			return nil, err
 		}
 		f.FrameType = ft
 	}
 	var reasonPhraseLen uint64
-	reasonPhraseLen, err = utils.ReadVarInt(r)
+	reasonPhraseLen, err = quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -60,9 +60,9 @@ func parseConnectionCloseFrame(r *bytes.Reader, _ protocol.VersionNumber) (*Conn
 
 // Length of a written frame
 func (f *ConnectionCloseFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
-	length := 1 + utils.VarIntLen(uint64(f.ErrorCode)) + utils.VarIntLen(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase))
+	length := 1 + quicvarint.Len(uint64(f.ErrorCode)) + quicvarint.Len(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase))
 	if !f.IsApplicationError {
-		length += utils.VarIntLen(f.FrameType) // for the frame type
+		length += quicvarint.Len(f.FrameType) // for the frame type
 	}
 	return length
 }
@@ -74,11 +74,11 @@ func (f *ConnectionCloseFrame) Write(b *bytes.Buffer, version protocol.VersionNu
 		b.WriteByte(0x1c)
 	}
 
-	utils.WriteVarInt(b, uint64(f.ErrorCode))
+	quicvarint.Write(b, uint64(f.ErrorCode))
 	if !f.IsApplicationError {
-		utils.WriteVarInt(b, f.FrameType)
+		quicvarint.Write(b, f.FrameType)
 	}
-	utils.WriteVarInt(b, uint64(len(f.ReasonPhrase)))
+	quicvarint.Write(b, uint64(len(f.ReasonPhrase)))
 	b.WriteString(f.ReasonPhrase)
 	return nil
 }

+ 8 - 8
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/crypto_frame.go

@@ -5,7 +5,7 @@ import (
 	"io"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A CryptoFrame is a CRYPTO frame
@@ -20,12 +20,12 @@ func parseCryptoFrame(r *bytes.Reader, _ protocol.VersionNumber) (*CryptoFrame,
 	}
 
 	frame := &CryptoFrame{}
-	offset, err := utils.ReadVarInt(r)
+	offset, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
 	frame.Offset = protocol.ByteCount(offset)
-	dataLen, err := utils.ReadVarInt(r)
+	dataLen, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -44,27 +44,27 @@ func parseCryptoFrame(r *bytes.Reader, _ protocol.VersionNumber) (*CryptoFrame,
 
 func (f *CryptoFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
 	b.WriteByte(0x6)
-	utils.WriteVarInt(b, uint64(f.Offset))
-	utils.WriteVarInt(b, uint64(len(f.Data)))
+	quicvarint.Write(b, uint64(f.Offset))
+	quicvarint.Write(b, uint64(len(f.Data)))
 	b.Write(f.Data)
 	return nil
 }
 
 // Length of a written frame
 func (f *CryptoFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
-	return 1 + utils.VarIntLen(uint64(f.Offset)) + utils.VarIntLen(uint64(len(f.Data))) + protocol.ByteCount(len(f.Data))
+	return 1 + quicvarint.Len(uint64(f.Offset)) + quicvarint.Len(uint64(len(f.Data))) + protocol.ByteCount(len(f.Data))
 }
 
 // MaxDataLen returns the maximum data length
 func (f *CryptoFrame) MaxDataLen(maxSize protocol.ByteCount) protocol.ByteCount {
 	// pretend that the data size will be 1 bytes
 	// if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards
-	headerLen := 1 + utils.VarIntLen(uint64(f.Offset)) + 1
+	headerLen := 1 + quicvarint.Len(uint64(f.Offset)) + 1
 	if headerLen > maxSize {
 		return 0
 	}
 	maxDataLen := maxSize - headerLen
-	if utils.VarIntLen(uint64(maxDataLen)) != 1 {
+	if quicvarint.Len(uint64(maxDataLen)) != 1 {
 		maxDataLen--
 	}
 	return maxDataLen

+ 4 - 4
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/data_blocked_frame.go

@@ -4,7 +4,7 @@ import (
 	"bytes"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A DataBlockedFrame is a DATA_BLOCKED frame
@@ -16,7 +16,7 @@ func parseDataBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*DataBloc
 	if _, err := r.ReadByte(); err != nil {
 		return nil, err
 	}
-	offset, err := utils.ReadVarInt(r)
+	offset, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -28,11 +28,11 @@ func parseDataBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*DataBloc
 func (f *DataBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
 	typeByte := uint8(0x14)
 	b.WriteByte(typeByte)
-	utils.WriteVarInt(b, uint64(f.MaximumData))
+	quicvarint.Write(b, uint64(f.MaximumData))
 	return nil
 }
 
 // Length of a written frame
 func (f *DataBlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
-	return 1 + utils.VarIntLen(uint64(f.MaximumData))
+	return 1 + quicvarint.Len(uint64(f.MaximumData))
 }

+ 85 - 0
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/datagram_frame.go

@@ -0,0 +1,85 @@
+package wire
+
+import (
+	"bytes"
+	"io"
+
+	"github.com/Psiphon-Labs/quic-go/internal/protocol"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
+)
+
+// A DatagramFrame is a DATAGRAM frame
+type DatagramFrame struct {
+	DataLenPresent bool
+	Data           []byte
+}
+
+func parseDatagramFrame(r *bytes.Reader, _ protocol.VersionNumber) (*DatagramFrame, error) {
+	typeByte, err := r.ReadByte()
+	if err != nil {
+		return nil, err
+	}
+
+	f := &DatagramFrame{}
+	f.DataLenPresent = typeByte&0x1 > 0
+
+	var length uint64
+	if f.DataLenPresent {
+		var err error
+		len, err := quicvarint.Read(r)
+		if err != nil {
+			return nil, err
+		}
+		if len > uint64(r.Len()) {
+			return nil, io.EOF
+		}
+		length = len
+	} else {
+		length = uint64(r.Len())
+	}
+	f.Data = make([]byte, length)
+	if _, err := io.ReadFull(r, f.Data); err != nil {
+		return nil, err
+	}
+	return f, nil
+}
+
+func (f *DatagramFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
+	typeByte := uint8(0x30)
+	if f.DataLenPresent {
+		typeByte ^= 0x1
+	}
+	b.WriteByte(typeByte)
+	if f.DataLenPresent {
+		quicvarint.Write(b, uint64(len(f.Data)))
+	}
+	b.Write(f.Data)
+	return nil
+}
+
+// MaxDataLen returns the maximum data length
+func (f *DatagramFrame) MaxDataLen(maxSize protocol.ByteCount, version protocol.VersionNumber) protocol.ByteCount {
+	headerLen := protocol.ByteCount(1)
+	if f.DataLenPresent {
+		// pretend that the data size will be 1 bytes
+		// if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards
+		headerLen++
+	}
+	if headerLen > maxSize {
+		return 0
+	}
+	maxDataLen := maxSize - headerLen
+	if f.DataLenPresent && quicvarint.Len(uint64(maxDataLen)) != 1 {
+		maxDataLen--
+	}
+	return maxDataLen
+}
+
+// Length of a written frame
+func (f *DatagramFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
+	length := 1 + protocol.ByteCount(len(f.Data))
+	if f.DataLenPresent {
+		length += quicvarint.Len(uint64(len(f.Data)))
+	}
+	return length
+}

+ 4 - 3
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/extended_header.go

@@ -8,6 +8,7 @@ import (
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // ErrInvalidReservedBits is returned when the reserved bits are incorrect.
@@ -158,10 +159,10 @@ func (h *ExtendedHeader) writeLongHeader(b *bytes.Buffer, _ protocol.VersionNumb
 		b.Write(h.Token)
 		return nil
 	case protocol.PacketTypeInitial:
-		utils.WriteVarInt(b, uint64(len(h.Token)))
+		quicvarint.Write(b, uint64(len(h.Token)))
 		b.Write(h.Token)
 	}
-	utils.WriteVarIntWithLen(b, uint64(h.Length), 2)
+	quicvarint.WriteWithLen(b, uint64(h.Length), 2)
 	return h.writePacketNumber(b)
 }
 
@@ -202,7 +203,7 @@ func (h *ExtendedHeader) GetLength(v protocol.VersionNumber) protocol.ByteCount
 	if h.IsLongHeader {
 		length := 1 /* type byte */ + 4 /* version */ + 1 /* dest conn ID len */ + protocol.ByteCount(h.DestConnectionID.Len()) + 1 /* src conn ID len */ + protocol.ByteCount(h.SrcConnectionID.Len()) + protocol.ByteCount(h.PacketNumberLen) + 2 /* length */
 		if h.Type == protocol.PacketTypeInitial {
-			length += utils.VarIntLen(uint64(len(h.Token))) + protocol.ByteCount(len(h.Token))
+			length += quicvarint.Len(uint64(len(h.Token))) + protocol.ByteCount(len(h.Token))
 		}
 		return length
 	}

+ 13 - 2
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/frame_parser.go

@@ -13,12 +13,17 @@ import (
 type frameParser struct {
 	ackDelayExponent uint8
 
+	supportsDatagrams bool
+
 	version protocol.VersionNumber
 }
 
 // NewFrameParser creates a new frame parser.
-func NewFrameParser(v protocol.VersionNumber) FrameParser {
-	return &frameParser{version: v}
+func NewFrameParser(supportsDatagrams bool, v protocol.VersionNumber) FrameParser {
+	return &frameParser{
+		supportsDatagrams: supportsDatagrams,
+		version:           v,
+	}
 }
 
 // ParseNextFrame parses the next frame
@@ -87,6 +92,12 @@ func (p *frameParser) parseFrame(r *bytes.Reader, typeByte byte, encLevel protoc
 			frame, err = parseConnectionCloseFrame(r, p.version)
 		case 0x1e:
 			frame, err = parseHandshakeDoneFrame(r, p.version)
+		case 0x30, 0x31:
+			if p.supportsDatagrams {
+				frame, err = parseDatagramFrame(r, p.version)
+				break
+			}
+			fallthrough
 		default:
 			err = errors.New("unknown frame type")
 		}

+ 19 - 2
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/header.go

@@ -2,12 +2,14 @@ package wire
 
 import (
 	"bytes"
+	"encoding/binary"
 	"errors"
 	"fmt"
 	"io"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
 	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // ParseConnectionID parses the destination connection ID of a packet.
@@ -42,6 +44,21 @@ func IsVersionNegotiationPacket(b []byte) bool {
 	return b[0]&0x80 > 0 && b[1] == 0 && b[2] == 0 && b[3] == 0 && b[4] == 0
 }
 
+// Is0RTTPacket says if this is a 0-RTT packet.
+// A packet sent with a version we don't understand can never be a 0-RTT packet.
+func Is0RTTPacket(b []byte) bool {
+	if len(b) < 5 {
+		return false
+	}
+	if b[0]&0x80 == 0 {
+		return false
+	}
+	if !protocol.IsSupportedVersion(protocol.SupportedVersions, protocol.VersionNumber(binary.BigEndian.Uint32(b[1:5]))) {
+		return false
+	}
+	return b[0]&0x30>>4 == 0x1
+}
+
 var ErrUnsupportedVersion = errors.New("unsupported version")
 
 // The Header is the version independent part of the header
@@ -187,7 +204,7 @@ func (h *Header) parseLongHeader(b *bytes.Reader) error {
 	}
 
 	if h.Type == protocol.PacketTypeInitial {
-		tokenLen, err := utils.ReadVarInt(b)
+		tokenLen, err := quicvarint.Read(b)
 		if err != nil {
 			return err
 		}
@@ -200,7 +217,7 @@ func (h *Header) parseLongHeader(b *bytes.Reader) error {
 		}
 	}
 
-	pl, err := utils.ReadVarInt(b)
+	pl, err := quicvarint.Read(b)
 	if err != nil {
 		return err
 	}

+ 4 - 4
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/max_data_frame.go

@@ -4,7 +4,7 @@ import (
 	"bytes"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A MaxDataFrame carries flow control information for the connection
@@ -19,7 +19,7 @@ func parseMaxDataFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxDataFrame
 	}
 
 	frame := &MaxDataFrame{}
-	byteOffset, err := utils.ReadVarInt(r)
+	byteOffset, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -30,11 +30,11 @@ func parseMaxDataFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxDataFrame
 // Write writes a MAX_STREAM_DATA frame
 func (f *MaxDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
 	b.WriteByte(0x10)
-	utils.WriteVarInt(b, uint64(f.MaximumData))
+	quicvarint.Write(b, uint64(f.MaximumData))
 	return nil
 }
 
 // Length of a written frame
 func (f *MaxDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
-	return 1 + utils.VarIntLen(uint64(f.MaximumData))
+	return 1 + quicvarint.Len(uint64(f.MaximumData))
 }

+ 6 - 6
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/max_stream_data_frame.go

@@ -4,7 +4,7 @@ import (
 	"bytes"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A MaxStreamDataFrame is a MAX_STREAM_DATA frame
@@ -18,11 +18,11 @@ func parseMaxStreamDataFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxStr
 		return nil, err
 	}
 
-	sid, err := utils.ReadVarInt(r)
+	sid, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
-	offset, err := utils.ReadVarInt(r)
+	offset, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -35,12 +35,12 @@ func parseMaxStreamDataFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxStr
 
 func (f *MaxStreamDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
 	b.WriteByte(0x11)
-	utils.WriteVarInt(b, uint64(f.StreamID))
-	utils.WriteVarInt(b, uint64(f.MaximumStreamData))
+	quicvarint.Write(b, uint64(f.StreamID))
+	quicvarint.Write(b, uint64(f.MaximumStreamData))
 	return nil
 }
 
 // Length of a written frame
 func (f *MaxStreamDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
-	return 1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.MaximumStreamData))
+	return 1 + quicvarint.Len(uint64(f.StreamID)) + quicvarint.Len(uint64(f.MaximumStreamData))
 }

+ 4 - 4
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/max_streams_frame.go

@@ -5,7 +5,7 @@ import (
 	"fmt"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A MaxStreamsFrame is a MAX_STREAMS frame
@@ -27,7 +27,7 @@ func parseMaxStreamsFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxStream
 	case 0x13:
 		f.Type = protocol.StreamTypeUni
 	}
-	streamID, err := utils.ReadVarInt(r)
+	streamID, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -45,11 +45,11 @@ func (f *MaxStreamsFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error
 	case protocol.StreamTypeUni:
 		b.WriteByte(0x13)
 	}
-	utils.WriteVarInt(b, uint64(f.MaxStreamNum))
+	quicvarint.Write(b, uint64(f.MaxStreamNum))
 	return nil
 }
 
 // Length of a written frame
 func (f *MaxStreamsFrame) Length(protocol.VersionNumber) protocol.ByteCount {
-	return 1 + utils.VarIntLen(uint64(f.MaxStreamNum))
+	return 1 + quicvarint.Len(uint64(f.MaxStreamNum))
 }

+ 6 - 7
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/new_connection_id_frame.go

@@ -5,9 +5,8 @@ import (
 	"fmt"
 	"io"
 
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
-
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A NewConnectionIDFrame is a NEW_CONNECTION_ID frame
@@ -23,11 +22,11 @@ func parseNewConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewC
 		return nil, err
 	}
 
-	seq, err := utils.ReadVarInt(r)
+	seq, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
-	ret, err := utils.ReadVarInt(r)
+	ret, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -63,8 +62,8 @@ func parseNewConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewC
 
 func (f *NewConnectionIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
 	b.WriteByte(0x18)
-	utils.WriteVarInt(b, f.SequenceNumber)
-	utils.WriteVarInt(b, f.RetirePriorTo)
+	quicvarint.Write(b, f.SequenceNumber)
+	quicvarint.Write(b, f.RetirePriorTo)
 	connIDLen := f.ConnectionID.Len()
 	if connIDLen > protocol.MaxConnIDLen {
 		return fmt.Errorf("invalid connection ID length: %d", connIDLen)
@@ -77,5 +76,5 @@ func (f *NewConnectionIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber)
 
 // Length of a written frame
 func (f *NewConnectionIDFrame) Length(protocol.VersionNumber) protocol.ByteCount {
-	return 1 + utils.VarIntLen(f.SequenceNumber) + utils.VarIntLen(f.RetirePriorTo) + 1 /* connection ID length */ + protocol.ByteCount(f.ConnectionID.Len()) + 16
+	return 1 + quicvarint.Len(f.SequenceNumber) + quicvarint.Len(f.RetirePriorTo) + 1 /* connection ID length */ + protocol.ByteCount(f.ConnectionID.Len()) + 16
 }

+ 4 - 4
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/new_token_frame.go

@@ -6,7 +6,7 @@ import (
 	"io"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A NewTokenFrame is a NEW_TOKEN frame
@@ -18,7 +18,7 @@ func parseNewTokenFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewTokenFra
 	if _, err := r.ReadByte(); err != nil {
 		return nil, err
 	}
-	tokenLen, err := utils.ReadVarInt(r)
+	tokenLen, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -37,12 +37,12 @@ func parseNewTokenFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewTokenFra
 
 func (f *NewTokenFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
 	b.WriteByte(0x7)
-	utils.WriteVarInt(b, uint64(len(f.Token)))
+	quicvarint.Write(b, uint64(len(f.Token)))
 	b.Write(f.Token)
 	return nil
 }
 
 // Length of a written frame
 func (f *NewTokenFrame) Length(protocol.VersionNumber) protocol.ByteCount {
-	return 1 + utils.VarIntLen(uint64(len(f.Token))) + protocol.ByteCount(len(f.Token))
+	return 1 + quicvarint.Len(uint64(len(f.Token))) + protocol.ByteCount(len(f.Token))
 }

+ 2 - 2
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/pool.go

@@ -11,7 +11,7 @@ var pool sync.Pool
 func init() {
 	pool.New = func() interface{} {
 		return &StreamFrame{
-			Data:     make([]byte, 0, protocol.MaxReceivePacketSize),
+			Data:     make([]byte, 0, protocol.MaxPacketBufferSize),
 			fromPool: true,
 		}
 	}
@@ -26,7 +26,7 @@ func putStreamFrame(f *StreamFrame) {
 	if !f.fromPool {
 		return
 	}
-	if protocol.ByteCount(cap(f.Data)) != protocol.MaxReceivePacketSize {
+	if protocol.ByteCount(cap(f.Data)) != protocol.MaxPacketBufferSize {
 		panic("wire.PutStreamFrame called with packet of wrong size!")
 	}
 	pool.Put(f)

+ 8 - 8
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/reset_stream_frame.go

@@ -4,7 +4,7 @@ import (
 	"bytes"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A ResetStreamFrame is a RESET_STREAM frame in QUIC
@@ -21,16 +21,16 @@ func parseResetStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*ResetStr
 
 	var streamID protocol.StreamID
 	var byteOffset protocol.ByteCount
-	sid, err := utils.ReadVarInt(r)
+	sid, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
 	streamID = protocol.StreamID(sid)
-	errorCode, err := utils.ReadVarInt(r)
+	errorCode, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
-	bo, err := utils.ReadVarInt(r)
+	bo, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -45,13 +45,13 @@ func parseResetStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*ResetStr
 
 func (f *ResetStreamFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
 	b.WriteByte(0x4)
-	utils.WriteVarInt(b, uint64(f.StreamID))
-	utils.WriteVarInt(b, uint64(f.ErrorCode))
-	utils.WriteVarInt(b, uint64(f.FinalSize))
+	quicvarint.Write(b, uint64(f.StreamID))
+	quicvarint.Write(b, uint64(f.ErrorCode))
+	quicvarint.Write(b, uint64(f.FinalSize))
 	return nil
 }
 
 // Length of a written frame
 func (f *ResetStreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
-	return 1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.ErrorCode)) + utils.VarIntLen(uint64(f.FinalSize))
+	return 1 + quicvarint.Len(uint64(f.StreamID)) + quicvarint.Len(uint64(f.ErrorCode)) + quicvarint.Len(uint64(f.FinalSize))
 }

+ 4 - 4
vendor/github.com/Psiphon-Labs/quic-go/internal/wire/retire_connection_id_frame.go

@@ -4,7 +4,7 @@ import (
 	"bytes"
 
 	"github.com/Psiphon-Labs/quic-go/internal/protocol"
-	"github.com/Psiphon-Labs/quic-go/internal/utils"
+	"github.com/Psiphon-Labs/quic-go/quicvarint"
 )
 
 // A RetireConnectionIDFrame is a RETIRE_CONNECTION_ID frame
@@ -17,7 +17,7 @@ func parseRetireConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*R
 		return nil, err
 	}
 
-	seq, err := utils.ReadVarInt(r)
+	seq, err := quicvarint.Read(r)
 	if err != nil {
 		return nil, err
 	}
@@ -26,11 +26,11 @@ func parseRetireConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*R
 
 func (f *RetireConnectionIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
 	b.WriteByte(0x19)
-	utils.WriteVarInt(b, f.SequenceNumber)
+	quicvarint.Write(b, f.SequenceNumber)
 	return nil
 }
 
 // Length of a written frame
 func (f *RetireConnectionIDFrame) Length(protocol.VersionNumber) protocol.ByteCount {
-	return 1 + utils.VarIntLen(f.SequenceNumber)
+	return 1 + quicvarint.Len(f.SequenceNumber)
 }

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff