Browse Source

Use Psiphon-Labs/utls@185b54f7

Amir Khan 1 year ago
parent
commit
8c91d53aba

+ 2 - 0
go.mod

@@ -29,6 +29,8 @@ replace github.com/pion/ice/v2 => ./replace/ice
 
 
 replace github.com/pion/webrtc/v3 => ./replace/webrtc
 replace github.com/pion/webrtc/v3 => ./replace/webrtc
 
 
+replace github.com/refraction-networking/utls => github.com/Psiphon-Labs/utls v1.1.1-0.20240807185429-185b54f73f17
+
 require (
 require (
 	filippo.io/edwards25519 v1.1.0
 	filippo.io/edwards25519 v1.1.0
 	github.com/Psiphon-Inc/rotate-safe-writer v0.0.0-20210303140923-464a7a37606e
 	github.com/Psiphon-Inc/rotate-safe-writer v0.0.0-20210303140923-464a7a37606e

+ 2 - 2
go.sum

@@ -22,6 +22,8 @@ github.com/Psiphon-Labs/psiphon-tls v0.0.0-20240716162946-891a0d5db073 h1:qOr7Ja
 github.com/Psiphon-Labs/psiphon-tls v0.0.0-20240716162946-891a0d5db073/go.mod h1:AaKKoshr8RI1LZTheeNDtNuZ39qNVPWVK4uir2c2XIs=
 github.com/Psiphon-Labs/psiphon-tls v0.0.0-20240716162946-891a0d5db073/go.mod h1:AaKKoshr8RI1LZTheeNDtNuZ39qNVPWVK4uir2c2XIs=
 github.com/Psiphon-Labs/quic-go v0.0.0-20240424181006-45545f5e1536 h1:pM5ex1QufkHV8lDR6Tc1Crk1bW5lYZjrFIJGZNBWE9k=
 github.com/Psiphon-Labs/quic-go v0.0.0-20240424181006-45545f5e1536 h1:pM5ex1QufkHV8lDR6Tc1Crk1bW5lYZjrFIJGZNBWE9k=
 github.com/Psiphon-Labs/quic-go v0.0.0-20240424181006-45545f5e1536/go.mod h1:2MTiPsgoOqWs3Bo6Xr3ElMBX6zzfjd3YkDFpQJLwHdQ=
 github.com/Psiphon-Labs/quic-go v0.0.0-20240424181006-45545f5e1536/go.mod h1:2MTiPsgoOqWs3Bo6Xr3ElMBX6zzfjd3YkDFpQJLwHdQ=
+github.com/Psiphon-Labs/utls v1.1.1-0.20240807185429-185b54f73f17 h1:7XPQc6Izr5cMOWdggqFxXIyNQmzabPre5kwXHhV3pl4=
+github.com/Psiphon-Labs/utls v1.1.1-0.20240807185429-185b54f73f17/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
 github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
 github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA=
 github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
 github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
 github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
 github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
@@ -222,8 +224,6 @@ github.com/refraction-networking/gotapdance v1.7.10 h1:vPtvuihP95SqrnnpX//KI1PTq
 github.com/refraction-networking/gotapdance v1.7.10/go.mod h1:N7Xmt+/bLv+1VctiBHtsaL6YBknW2ox5LRLzPTISMzY=
 github.com/refraction-networking/gotapdance v1.7.10/go.mod h1:N7Xmt+/bLv+1VctiBHtsaL6YBknW2ox5LRLzPTISMzY=
 github.com/refraction-networking/obfs4 v0.1.2 h1:J842O4fGSkd2W8ogYj0KN6gqVVY+Cpqodw9qFGL7wVU=
 github.com/refraction-networking/obfs4 v0.1.2 h1:J842O4fGSkd2W8ogYj0KN6gqVVY+Cpqodw9qFGL7wVU=
 github.com/refraction-networking/obfs4 v0.1.2/go.mod h1:wAl/+gWiLsrcykJA3nKJHx89f5/gXGM8UKvty7+mvbM=
 github.com/refraction-networking/obfs4 v0.1.2/go.mod h1:wAl/+gWiLsrcykJA3nKJHx89f5/gXGM8UKvty7+mvbM=
-github.com/refraction-networking/utls v1.6.8-0.20240720032424-23de245734c7 h1:2D69ZJ8F+kPHFTQp4jF6GQ80eZWXDUwWf1JWsGMak0M=
-github.com/refraction-networking/utls v1.6.8-0.20240720032424-23de245734c7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
 github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
 github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=

+ 17 - 5
vendor/github.com/refraction-networking/utls/handshake_client_tls13.go

@@ -14,6 +14,7 @@ import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"hash"
 	"hash"
+	"log"
 	"time"
 	"time"
 
 
 	"github.com/cloudflare/circl/kem"
 	"github.com/cloudflare/circl/kem"
@@ -410,11 +411,6 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
 	// and utlsExtensionPadding are supposed to change
 	// and utlsExtensionPadding are supposed to change
 	if hs.uconn != nil {
 	if hs.uconn != nil {
 		if hs.uconn.ClientHelloID != HelloGolang {
 		if hs.uconn.ClientHelloID != HelloGolang {
-			if len(hs.hello.pskIdentities) > 0 {
-				// TODO: wait for someone who cares about PSK to implement
-				return errors.New("uTLS does not support reprocessing of PSK key triggered by HelloRetryRequest")
-			}
-
 			keyShareExtFound := false
 			keyShareExtFound := false
 			for _, ext := range hs.uconn.Extensions {
 			for _, ext := range hs.uconn.Extensions {
 				// new ks seems to be generated either way
 				// new ks seems to be generated either way
@@ -459,6 +455,22 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
 			if err := hs.uconn.MarshalClientHello(); err != nil {
 			if err := hs.uconn.MarshalClientHello(); err != nil {
 				return err
 				return err
 			}
 			}
+
+			if len(hs.hello.pskIdentities) > 0 {
+				for _, ext := range hs.uconn.Extensions {
+					if psk, ok := ext.(PreSharedKeyExtension); ok {
+						if err := psk.UpdateOnHRR(chHash, hs, c.config.time()); err != nil {
+							hs.uconn.HandshakeState.Hello.PskIdentities = nil
+							hs.uconn.HandshakeState.Hello.PskBinders = nil
+							log.Printf("[Error] PreSharedKeyExtension.UpdateOnHRR failed: %v", err)
+						} else {
+							psk.PatchBuiltHello(hs.uconn.HandshakeState.Hello)
+						}
+						break
+					}
+				}
+			}
+
 			hs.hello.raw = hs.uconn.HandshakeState.Hello.Raw
 			hs.hello.raw = hs.uconn.HandshakeState.Hello.Raw
 		}
 		}
 	}
 	}

+ 1 - 0
vendor/github.com/refraction-networking/utls/u_common.go

@@ -612,6 +612,7 @@ var (
 	// Chrome w/ PSK: Chrome start sending this ClientHello after doing TLS 1.3 handshake with the same server.
 	// Chrome w/ PSK: Chrome start sending this ClientHello after doing TLS 1.3 handshake with the same server.
 	// Beta: PSK extension added. However, uTLS doesn't ship with full PSK support.
 	// Beta: PSK extension added. However, uTLS doesn't ship with full PSK support.
 	// Use at your own discretion.
 	// Use at your own discretion.
+	HelloChrome_PSK_Auto             = HelloChrome_114_Padding_PSK_Shuf
 	HelloChrome_100_PSK              = ClientHelloID{helloChrome, "100_PSK", nil, nil}
 	HelloChrome_100_PSK              = ClientHelloID{helloChrome, "100_PSK", nil, nil}
 	HelloChrome_112_PSK_Shuf         = ClientHelloID{helloChrome, "112_PSK", nil, nil}
 	HelloChrome_112_PSK_Shuf         = ClientHelloID{helloChrome, "112_PSK", nil, nil}
 	HelloChrome_114_Padding_PSK_Shuf = ClientHelloID{helloChrome, "114_PSK", nil, nil}
 	HelloChrome_114_Padding_PSK_Shuf = ClientHelloID{helloChrome, "114_PSK", nil, nil}

+ 81 - 7
vendor/github.com/refraction-networking/utls/u_pre_shared_key.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"io"
 	"io"
+	"time"
 
 
 	"golang.org/x/crypto/cryptobyte"
 	"golang.org/x/crypto/cryptobyte"
 )
 )
@@ -68,6 +69,26 @@ type PreSharedKeyCommon struct {
 //     > - Implementations should gather and provide the final pre-shared key (PSK) related data.
 //     > - Implementations should gather and provide the final pre-shared key (PSK) related data.
 //
 //
 //     > - This data will be incorporated into both the clientHello and HandshakeState, ensuring that the PSK-related information is properly set and ready for the handshake process.
 //     > - This data will be incorporated into both the clientHello and HandshakeState, ensuring that the PSK-related information is properly set and ready for the handshake process.
+//
+// HelloRetryRequest Phase (server selects a different curve supported but not selected by the client):
+//
+//   - [UpdateOnHRR() called]:
+//
+//     > - Implementations should update the extension's state accordingly and save the first Client Hello's hash.
+//
+//     > - The binders should be recalculated based on the updated state LATER when PatchBuiltHello() and/or GetPreSharedKeyCommon() is called.
+//
+//   - [PatchBuiltHello() called]:
+//
+//     > - The client hello is already marshaled in the "hello.Raw" format.
+//
+//     > - Implementations are expected to update the binders within the marshaled client hello.
+//
+//   - [GetPreSharedKeyCommon() called]:
+//
+//     > - Implementations should gather and provide the final pre-shared key (PSK) related data.
+//
+//     > - This data will be incorporated into both the clientHello and HandshakeState, ensuring that the PSK-related information is properly set and ready for the handshake process.
 type PreSharedKeyExtension interface {
 type PreSharedKeyExtension interface {
 	// TLSExtension must be implemented by all PreSharedKeyExtension implementations.
 	// TLSExtension must be implemented by all PreSharedKeyExtension implementations.
 	TLSExtension
 	TLSExtension
@@ -88,6 +109,11 @@ type PreSharedKeyExtension interface {
 	// Its purpose is to update the binders of PSK (Pre-Shared Key) identities.
 	// Its purpose is to update the binders of PSK (Pre-Shared Key) identities.
 	PatchBuiltHello(hello *PubClientHelloMsg) error
 	PatchBuiltHello(hello *PubClientHelloMsg) error
 
 
+	// UpdateOnHRR is called when the server sends a HelloRetryRequest.
+	// Implementations should update the extension's state accordingly
+	// and recalculate the binders.
+	UpdateOnHRR(prevClientHelloHash []byte, hs *clientHandshakeStateTLS13, timeNow time.Time) error
+
 	mustEmbedUnimplementedPreSharedKeyExtension() // this works like a type guard
 	mustEmbedUnimplementedPreSharedKeyExtension() // this works like a type guard
 }
 }
 
 
@@ -99,7 +125,7 @@ func (*UnimplementedPreSharedKeyExtension) IsInitialized() bool {
 	panic("tls: IsInitialized is not implemented for the PreSharedKeyExtension")
 	panic("tls: IsInitialized is not implemented for the PreSharedKeyExtension")
 }
 }
 
 
-func (*UnimplementedPreSharedKeyExtension) InitializeByUtls(session *SessionState, earlySecret []byte, binderKey []byte, identities []PskIdentity) {
+func (*UnimplementedPreSharedKeyExtension) InitializeByUtls(*SessionState, []byte, []byte, []PskIdentity) {
 	panic("tls: Initialize is not implemented for the PreSharedKeyExtension")
 	panic("tls: Initialize is not implemented for the PreSharedKeyExtension")
 }
 }
 
 
@@ -119,14 +145,18 @@ func (*UnimplementedPreSharedKeyExtension) GetPreSharedKeyCommon() PreSharedKeyC
 	panic("tls: GetPreSharedKeyCommon is not implemented for the PreSharedKeyExtension")
 	panic("tls: GetPreSharedKeyCommon is not implemented for the PreSharedKeyExtension")
 }
 }
 
 
-func (*UnimplementedPreSharedKeyExtension) PatchBuiltHello(hello *PubClientHelloMsg) error {
+func (*UnimplementedPreSharedKeyExtension) PatchBuiltHello(*PubClientHelloMsg) error {
 	panic("tls: ReadWithRawHello is not implemented for the PreSharedKeyExtension")
 	panic("tls: ReadWithRawHello is not implemented for the PreSharedKeyExtension")
 }
 }
 
 
-func (*UnimplementedPreSharedKeyExtension) SetOmitEmptyPsk(val bool) {
+func (*UnimplementedPreSharedKeyExtension) SetOmitEmptyPsk(bool) {
 	panic("tls: SetOmitEmptyPsk is not implemented for the PreSharedKeyExtension")
 	panic("tls: SetOmitEmptyPsk is not implemented for the PreSharedKeyExtension")
 }
 }
 
 
+func (*UnimplementedPreSharedKeyExtension) UpdateOnHRR([]byte, *clientHandshakeStateTLS13, time.Time) error {
+	panic("tls: UpdateOnHRR is not implemented for the PreSharedKeyExtension")
+}
+
 // UtlsPreSharedKeyExtension is an extension used to set the PSK extension in the
 // UtlsPreSharedKeyExtension is an extension used to set the PSK extension in the
 // ClientHello.
 // ClientHello.
 type UtlsPreSharedKeyExtension struct {
 type UtlsPreSharedKeyExtension struct {
@@ -136,6 +166,10 @@ type UtlsPreSharedKeyExtension struct {
 	cachedLength *int
 	cachedLength *int
 	// Deprecated: Set OmitEmptyPsk in Config instead.
 	// Deprecated: Set OmitEmptyPsk in Config instead.
 	OmitEmptyPsk bool
 	OmitEmptyPsk bool
+
+	// used only for HRR-based recalculation of binders purpose
+	prevClientHelloHash []byte // used for HRR-based recalculation of binders
+	serverHello         *serverHelloMsg
 }
 }
 
 
 func (e *UtlsPreSharedKeyExtension) IsInitialized() bool {
 func (e *UtlsPreSharedKeyExtension) IsInitialized() bool {
@@ -265,6 +299,7 @@ func (e *UtlsPreSharedKeyExtension) PatchBuiltHello(hello *PubClientHelloMsg) er
 	if e.Len() == 0 {
 	if e.Len() == 0 {
 		return nil
 		return nil
 	}
 	}
+
 	private := hello.getCachedPrivatePtr()
 	private := hello.getCachedPrivatePtr()
 	if private == nil {
 	if private == nil {
 		private = hello.getPrivatePtr()
 		private = hello.getPrivatePtr()
@@ -272,8 +307,17 @@ func (e *UtlsPreSharedKeyExtension) PatchBuiltHello(hello *PubClientHelloMsg) er
 	private.raw = hello.Raw
 	private.raw = hello.Raw
 	private.pskBinders = e.Binders // set the placeholder to the private Hello
 	private.pskBinders = e.Binders // set the placeholder to the private Hello
 
 
-	//--- mirror loadSession() begin ---//
+	// derived from loadSession() and processHelloRetryRequest() begin //
 	transcript := e.cipherSuite.hash.New()
 	transcript := e.cipherSuite.hash.New()
+
+	if len(e.prevClientHelloHash) > 0 { // HRR will set this field
+		transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(e.prevClientHelloHash))})
+		transcript.Write(e.prevClientHelloHash)
+		if err := transcriptMsg(e.serverHello, transcript); err != nil {
+			return err
+		}
+	}
+
 	helloBytes, err := private.marshalWithoutBinders() // no marshal() will be actually called, as we have set the field `raw`
 	helloBytes, err := private.marshalWithoutBinders() // no marshal() will be actually called, as we have set the field `raw`
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -284,7 +328,7 @@ func (e *UtlsPreSharedKeyExtension) PatchBuiltHello(hello *PubClientHelloMsg) er
 	if err := private.updateBinders(pskBinders); err != nil {
 	if err := private.updateBinders(pskBinders); err != nil {
 		return err
 		return err
 	}
 	}
-	//--- mirror loadSession() end ---//
+	// derived end //
 	e.Binders = pskBinders
 	e.Binders = pskBinders
 
 
 	// no need to care about other PSK related fields, they will be handled separately
 	// no need to care about other PSK related fields, they will be handled separately
@@ -292,11 +336,35 @@ func (e *UtlsPreSharedKeyExtension) PatchBuiltHello(hello *PubClientHelloMsg) er
 	return io.EOF
 	return io.EOF
 }
 }
 
 
+func (e *UtlsPreSharedKeyExtension) UpdateOnHRR(prevClientHelloHash []byte, hs *clientHandshakeStateTLS13, timeNow time.Time) error {
+	if len(e.Identities) > 0 {
+		e.Session = hs.session
+		e.cipherSuite = cipherSuiteTLS13ByID(e.Session.cipherSuite)
+		if e.cipherSuite.hash != hs.suite.hash {
+			// disable PatchBuiltHello
+			e.Session = nil
+			e.cachedLength = new(int)
+			return errors.New("tls: cipher suite hash mismatch, PSK will not be used")
+		}
+
+		// update the obfuscated ticket age
+		ticketAge := timeNow.Sub(time.Unix(int64(hs.session.createdAt), 0))
+		e.Identities[0].ObfuscatedTicketAge = uint32(ticketAge/time.Millisecond) + hs.session.ageAdd
+
+		// e.Binders = nil
+		e.cachedLength = nil // clear the cached length
+
+		e.prevClientHelloHash = prevClientHelloHash
+		e.serverHello = hs.serverHello
+	}
+	return nil
+}
+
 func (e *UtlsPreSharedKeyExtension) Write(b []byte) (int, error) {
 func (e *UtlsPreSharedKeyExtension) Write(b []byte) (int, error) {
 	return len(b), nil // ignore the data
 	return len(b), nil // ignore the data
 }
 }
 
 
-func (e *UtlsPreSharedKeyExtension) UnmarshalJSON(_ []byte) error {
+func (e *UtlsPreSharedKeyExtension) UnmarshalJSON([]byte) error {
 	return nil // ignore the data
 	return nil // ignore the data
 }
 }
 
 
@@ -319,7 +387,7 @@ func (e *FakePreSharedKeyExtension) IsInitialized() bool {
 	return e.Identities != nil && e.Binders != nil
 	return e.Identities != nil && e.Binders != nil
 }
 }
 
 
-func (e *FakePreSharedKeyExtension) InitializeByUtls(session *SessionState, earlySecret []byte, binderKey []byte, identities []PskIdentity) {
+func (e *FakePreSharedKeyExtension) InitializeByUtls(*SessionState, []byte, []byte, []PskIdentity) {
 	panic("InitializeByUtls failed: don't let utls initialize FakePreSharedKeyExtension; provide your own identities and binders or use UtlsPreSharedKeyExtension")
 	panic("InitializeByUtls failed: don't let utls initialize FakePreSharedKeyExtension; provide your own identities and binders or use UtlsPreSharedKeyExtension")
 }
 }
 
 
@@ -459,13 +527,19 @@ func (e *FakePreSharedKeyExtension) UnmarshalJSON(data []byte) error {
 	return nil
 	return nil
 }
 }
 
 
+func (e *FakePreSharedKeyExtension) UpdateOnHRR([]byte, *clientHandshakeStateTLS13, time.Time) error {
+	return nil
+}
+
 // type guard
 // type guard
 var (
 var (
 	_ PreSharedKeyExtension = (*UtlsPreSharedKeyExtension)(nil)
 	_ PreSharedKeyExtension = (*UtlsPreSharedKeyExtension)(nil)
 	_ TLSExtensionJSON      = (*UtlsPreSharedKeyExtension)(nil)
 	_ TLSExtensionJSON      = (*UtlsPreSharedKeyExtension)(nil)
+	_ TLSExtensionWriter    = (*UtlsPreSharedKeyExtension)(nil)
 	_ PreSharedKeyExtension = (*FakePreSharedKeyExtension)(nil)
 	_ PreSharedKeyExtension = (*FakePreSharedKeyExtension)(nil)
 	_ TLSExtensionJSON      = (*FakePreSharedKeyExtension)(nil)
 	_ TLSExtensionJSON      = (*FakePreSharedKeyExtension)(nil)
 	_ TLSExtensionWriter    = (*FakePreSharedKeyExtension)(nil)
 	_ TLSExtensionWriter    = (*FakePreSharedKeyExtension)(nil)
+	_ PreSharedKeyExtension = (*UnimplementedPreSharedKeyExtension)(nil)
 )
 )
 
 
 // type ExternalPreSharedKeyExtension struct{} // TODO: wait for whoever cares about external PSK to implement it
 // type ExternalPreSharedKeyExtension struct{} // TODO: wait for whoever cares about external PSK to implement it

+ 1 - 1
vendor/github.com/refraction-networking/utls/u_session_controller.go

@@ -223,7 +223,7 @@ func (s *sessionController) shouldUpdateBinders() bool {
 
 
 func (s *sessionController) updateBinders() {
 func (s *sessionController) updateBinders() {
 	uAssert(s.shouldUpdateBinders(), "tls: updateBinders failed: shouldn't update binders")
 	uAssert(s.shouldUpdateBinders(), "tls: updateBinders failed: shouldn't update binders")
-	s.pskExtension.PatchBuiltHello(s.uconnRef.HandshakeState.Hello)
+	s.pskExtension.PatchBuiltHello(s.uconnRef.HandshakeState.Hello) // bugrisk: retured error is ignored
 }
 }
 
 
 func (s *sessionController) overrideExtension(extension Initializable, override func(), initializedState sessionControllerState) error {
 func (s *sessionController) overrideExtension(extension Initializable, override func(), initializedState sessionControllerState) error {

+ 2 - 1
vendor/modules.txt

@@ -417,7 +417,7 @@ github.com/refraction-networking/obfs4/common/replayfilter
 github.com/refraction-networking/obfs4/transports/base
 github.com/refraction-networking/obfs4/transports/base
 github.com/refraction-networking/obfs4/transports/obfs4
 github.com/refraction-networking/obfs4/transports/obfs4
 github.com/refraction-networking/obfs4/transports/obfs4/framing
 github.com/refraction-networking/obfs4/transports/obfs4/framing
-# github.com/refraction-networking/utls v1.6.8-0.20240720032424-23de245734c7
+# github.com/refraction-networking/utls v1.6.8-0.20240720032424-23de245734c7 => github.com/Psiphon-Labs/utls v1.1.1-0.20240807185429-185b54f73f17
 ## explicit; go 1.21
 ## explicit; go 1.21
 github.com/refraction-networking/utls
 github.com/refraction-networking/utls
 github.com/refraction-networking/utls/dicttls
 github.com/refraction-networking/utls/dicttls
@@ -635,3 +635,4 @@ tailscale.com/version/distro
 # github.com/pion/dtls/v2 => ./replace/dtls
 # github.com/pion/dtls/v2 => ./replace/dtls
 # github.com/pion/ice/v2 => ./replace/ice
 # github.com/pion/ice/v2 => ./replace/ice
 # github.com/pion/webrtc/v3 => ./replace/webrtc
 # github.com/pion/webrtc/v3 => ./replace/webrtc
+# github.com/refraction-networking/utls => github.com/Psiphon-Labs/utls v1.1.1-0.20240807185429-185b54f73f17