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

Add longer lived cache for HTTPS MEEK and TLS-OSSH

Amir Khan 2 лет назад
Родитель
Сommit
bc02e8a967

+ 8 - 7
psiphon/dialParameters.go

@@ -168,9 +168,9 @@ type DialParameters struct {
 	steeringIPCache    *lrucache.Cache `json:"-"`
 	steeringIPCacheKey string          `json:"-"`
 
-	quicTLSSessionCacheKey      string                  `json:"-"`
-	QUICTLSClientSessionCache   tls.ClientSessionCache  `json:"-"`
-	directTLSClientSessionCache utls.ClientSessionCache `json:"-"`
+	quicTLSSessionCacheKey    string                  `json:"-"`
+	QUICTLSClientSessionCache tls.ClientSessionCache  `json:"-"`
+	tlsClientSessionCache     utls.ClientSessionCache `json:"-"`
 
 	dialConfig *DialConfig `json:"-"`
 	meekConfig *MeekConfig `json:"-"`
@@ -197,7 +197,7 @@ func MakeDialParameters(
 	config *Config,
 	steeringIPCache *lrucache.Cache,
 	quicTLSClientSessionCache tls.ClientSessionCache,
-	directTLSClientSessionCache utls.ClientSessionCache,
+	tlsClientSessionCache utls.ClientSessionCache,
 	upstreamProxyErrorCallback func(error),
 	canReplay func(serverEntry *protocol.ServerEntry, replayProtocol string) bool,
 	selectProtocol func(serverEntry *protocol.ServerEntry) (string, bool),
@@ -371,7 +371,7 @@ func MakeDialParameters(
 
 	dialParams.steeringIPCache = steeringIPCache
 
-	dialParams.directTLSClientSessionCache = directTLSClientSessionCache
+	dialParams.tlsClientSessionCache = tlsClientSessionCache
 
 	dialParams.ServerEntry = serverEntry
 	dialParams.NetworkID = networkID
@@ -1329,7 +1329,8 @@ func MakeDialParameters(
 			QUICVersion:                   dialParams.QUICVersion,
 			QUICClientHelloSeed:           dialParams.QUICClientHelloSeed,
 			QUICDialEarly:                 dialParams.QUICDialEarly,
-			QuicTlsClientSessionCache:     dialParams.meekConfig.QuicTlsClientSessionCache,
+			QUICTLSClientSessionCache:     dialParams.QUICTLSClientSessionCache,
+			TLSClientSessionCache:         dialParams.tlsClientSessionCache,
 			QUICDisablePathMTUDiscovery:   dialParams.QUICDisablePathMTUDiscovery,
 			UseHTTPS:                      usingTLS,
 			TLSProfile:                    dialParams.TLSProfile,
@@ -1393,7 +1394,7 @@ func (dialParams *DialParameters) GetTLSOSSHConfig(config *Config) *TLSTunnelCon
 			NoDefaultTLSSessionID:    &dialParams.NoDefaultTLSSessionID,
 			RandomizedTLSProfileSeed: dialParams.RandomizedTLSProfileSeed,
 			FragmentClientHello:      dialParams.TLSFragmentClientHello,
-			ClientSessionCache:       dialParams.directTLSClientSessionCache,
+			ClientSessionCache:       dialParams.tlsClientSessionCache,
 		},
 		// Obfuscated session tickets are not used because TLS-OSSH uses TLS 1.3.
 		UseObfuscatedSessionTickets: false,

+ 21 - 21
psiphon/dialParameters_test.go

@@ -151,7 +151,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	upstreamProxyErrorCallback := func(_ error) {}
 
 	dialParams, err := MakeDialParameters(
-		clientConfig, steeringIPCache, upstreamProxyErrorCallback, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, upstreamProxyErrorCallback, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -275,7 +275,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	dialParams.Failed(clientConfig)
 
 	dialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -291,7 +291,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	testNetworkID = prng.HexString(8)
 
 	dialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -309,7 +309,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	dialParams.Succeeded()
 
 	replayDialParams, err := MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -421,7 +421,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	}
 
 	dialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -440,7 +440,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	}
 
 	dialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -456,7 +456,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	time.Sleep(1 * time.Second)
 
 	dialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -472,7 +472,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	serverEntries[0].ConfigurationVersion += 1
 
 	dialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -496,7 +496,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	}
 
 	dialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -504,7 +504,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	dialParams.Succeeded()
 
 	replayDialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 	if err != nil {
 		t.Fatalf("MakeDialParameters failed: %s", err)
 	}
@@ -537,7 +537,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	}
 
 	dialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 
 	if protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) {
 		if err == nil {
@@ -567,7 +567,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 	}
 
 	dialParams, err = MakeDialParameters(
-		clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+		clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 
 	if protocol.TunnelProtocolIsDirect(tunnelProtocol) {
 		if err == nil {
@@ -595,7 +595,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 		// Test: steering IP used in non-replay case
 
 		dialParams, err = MakeDialParameters(
-			clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+			clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 		if err != nil {
 			t.Fatalf("MakeDialParameters failed: %s", err)
 		}
@@ -613,7 +613,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 		setCacheEntry("127.0.0.1")
 
 		dialParams, err = MakeDialParameters(
-			clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+			clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 		if err != nil {
 			t.Fatalf("MakeDialParameters failed: %s", err)
 		}
@@ -641,7 +641,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 		dialParams.Succeeded()
 
 		dialParams, err = MakeDialParameters(
-			clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+			clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 		if err != nil {
 			t.Fatalf("MakeDialParameters failed: %s", err)
 		}
@@ -659,7 +659,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 		setCacheEntry("127.0.0.2")
 
 		dialParams, err = MakeDialParameters(
-			clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+			clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 		if err != nil {
 			t.Fatalf("MakeDialParameters failed: %s", err)
 		}
@@ -675,7 +675,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 		steeringIPCache.Flush()
 
 		dialParams, err = MakeDialParameters(
-			clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+			clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 		if err != nil {
 			t.Fatalf("MakeDialParameters failed: %s", err)
 		}
@@ -685,7 +685,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 		setCacheEntry("127.0.0.3")
 
 		dialParams, err = MakeDialParameters(
-			clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
+			clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntries[0], false, 0, 0)
 		if err != nil {
 			t.Fatalf("MakeDialParameters failed: %s", err)
 		}
@@ -727,7 +727,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 		if i%10 == 0 {
 
 			dialParams, err := MakeDialParameters(
-				clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
+				clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
 			if err != nil {
 				t.Fatalf("MakeDialParameters failed: %s", err)
 			}
@@ -757,7 +757,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 			}
 
 			dialParams, err := MakeDialParameters(
-				clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
+				clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
 			if err != nil {
 				t.Fatalf("MakeDialParameters failed: %s", err)
 			}
@@ -780,7 +780,7 @@ func runDialParametersAndReplay(t *testing.T, tunnelProtocol string) {
 			}
 
 			dialParams, err := MakeDialParameters(
-				clientConfig, steeringIPCache, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
+				clientConfig, steeringIPCache, nil, nil, nil, canReplay, selectProtocol, serverEntry, false, 0, 0)
 			if err != nil {
 				t.Fatalf("MakeDialParameters failed: %s", err)
 			}

+ 2 - 0
psiphon/exchange_test.go

@@ -187,6 +187,8 @@ func TestServerEntryExchange(t *testing.T) {
 				config,
 				nil,
 				nil,
+				nil,
+				nil,
 				canReplay,
 				selectProtocol,
 				serverEntry,

+ 16 - 6
psiphon/meekConn.go

@@ -48,6 +48,7 @@ import (
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/transforms"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/upstreamproxy"
+	utls "github.com/refraction-networking/utls"
 	"golang.org/x/crypto/nacl/box"
 	"golang.org/x/net/http2"
 )
@@ -135,9 +136,13 @@ type MeekConfig struct {
 	// underlying TLS connections created by this meek connection.
 	TLSProfile string
 
-	// QuicTlsClientSessionCache specifies the TLS session cache to use
+	// QUICTLSClientSessionCache specifies the TLS session cache to use
 	// for Meek connections that use HTTP/2 over QUIC.
-	QuicTlsClientSessionCache tls.ClientSessionCache
+	QUICTLSClientSessionCache tls.ClientSessionCache
+
+	// TLSClientSessionCache specifies the TLS session cache to use for
+	// HTTPS (non-QUIC) Meek connections.
+	TLSClientSessionCache utls.ClientSessionCache
 
 	// TLSFragmentClientHello specifies whether to fragment the TLS Client Hello.
 	TLSFragmentClientHello bool
@@ -303,9 +308,14 @@ func DialMeek(
 			"invalid config: only one of UseQUIC or UseHTTPS may be set")
 	}
 
-	if meekConfig.UseQUIC && meekConfig.QuicTlsClientSessionCache == nil {
+	if meekConfig.UseQUIC && meekConfig.QUICTLSClientSessionCache == nil {
+		return nil, errors.TraceNew(
+			"invalid config: QUICTLSClientSessionCache must be set when UseQUIC is set")
+	}
+
+	if meekConfig.UseHTTPS && meekConfig.TLSClientSessionCache == nil {
 		return nil, errors.TraceNew(
-			"invalid config: TLSClientSessionCache must be set when UseQUIC is set")
+			"invalid config: TLSClientSessionCache must be set when UseHTTPS is set")
 	}
 
 	if meekConfig.UseQUIC &&
@@ -421,7 +431,7 @@ func DialMeek(
 			meekConfig.QUICClientHelloSeed,
 			meekConfig.QUICDisablePathMTUDiscovery,
 			meekConfig.QUICDialEarly,
-			meekConfig.QuicTlsClientSessionCache)
+			meekConfig.QUICTLSClientSessionCache)
 		if err != nil {
 			return nil, errors.Trace(err)
 		}
@@ -480,8 +490,8 @@ func DialMeek(
 			TLSPadding:                    meek.tlsPadding,
 			TrustedCACertificatesFilename: dialConfig.TrustedCACertificatesFilename,
 			FragmentClientHello:           meekConfig.TLSFragmentClientHello,
+			ClientSessionCache:            meekConfig.TLSClientSessionCache,
 		}
-		tlsConfig.EnableClientSessionCache()
 
 		if meekConfig.UseObfuscatedSessionTickets {
 			tlsConfig.ObfuscatedSessionTicketKey = meekConfig.MeekObfuscatedKey

+ 12 - 7
psiphon/meekConn_test.go

@@ -27,7 +27,9 @@ import (
 	"testing"
 	"time"
 
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
+	utls "github.com/refraction-networking/utls"
 )
 
 // MeekModeRelay and MeekModeObfuscatedRoundTrip are tested via meek protocol
@@ -57,14 +59,17 @@ func TestMeekModePlaintextRoundTrip(t *testing.T) {
 		t.Fatalf("parameters.NewParameters failed: %v", err)
 	}
 
+	tlsCache := common.WrapUtlsClientSessionCache(utls.NewLRUClientSessionCache(0), serverAddr)
+
 	meekConfig := &MeekConfig{
-		Parameters:       params,
-		Mode:             MeekModePlaintextRoundTrip,
-		DialAddress:      serverAddr,
-		UseHTTPS:         true,
-		SNIServerName:    "not-" + serverName,
-		VerifyServerName: serverName,
-		VerifyPins:       []string{rootCACertificatePin, serverCertificatePin},
+		Parameters:            params,
+		Mode:                  MeekModePlaintextRoundTrip,
+		DialAddress:           serverAddr,
+		UseHTTPS:              true,
+		SNIServerName:         "not-" + serverName,
+		VerifyServerName:      serverName,
+		VerifyPins:            []string{rootCACertificatePin, serverCertificatePin},
+		TLSClientSessionCache: tlsCache,
 	}
 
 	dialConfig := &DialConfig{

+ 2 - 0
psiphon/server/server_test.go

@@ -3298,6 +3298,8 @@ func storePruneServerEntriesTest(
 			clientConfig,
 			nil,
 			nil,
+			nil,
+			nil,
 			func(_ *protocol.ServerEntry, _ string) bool { return true },
 			func(serverEntry *protocol.ServerEntry) (string, bool) {
 				return runConfig.tunnelProtocol, true

+ 2 - 0
psiphon/server/sessionID_test.go

@@ -168,6 +168,8 @@ func TestDuplicateSessionID(t *testing.T) {
 			clientConfig,
 			nil,
 			nil,
+			nil,
+			nil,
 			func(_ *protocol.ServerEntry, _ string) bool { return false },
 			func(_ *protocol.ServerEntry) (string, bool) { return "OSSH", true },
 			serverEntry,

+ 1 - 0
psiphon/tlsDialer.go

@@ -184,6 +184,7 @@ type CustomTLSConfig struct {
 	// FragmentClientHello specifies whether to fragment the ClientHello.
 	FragmentClientHello bool
 
+	// ClientSessionCache specifies the cache to use to persist session tickets.
 	ClientSessionCache utls.ClientSessionCache
 }
 

+ 1 - 1
psiphon/tlsTunnelConn.go

@@ -87,8 +87,8 @@ func DialTLSTunnel(
 		TLSPadding:                    tlsPadding,
 		TrustedCACertificatesFilename: dialConfig.TrustedCACertificatesFilename,
 		FragmentClientHello:           tlsTunnelConfig.CustomTLSConfig.FragmentClientHello,
+		ClientSessionCache:            tlsTunnelConfig.CustomTLSConfig.ClientSessionCache,
 	}
-	tlsConfig.EnableClientSessionCache()
 
 	if tlsTunnelConfig.UseObfuscatedSessionTickets {
 		tlsConfig.ObfuscatedSessionTicketKey = tlsTunnelConfig.ObfuscatedKey