Procházet zdrojové kódy

Support configuring tactics key parameters in psiphond.config

Rod Hynes před 6 měsíci
rodič
revize
6560abad28

+ 32 - 1
psiphon/common/tactics/tactics.go

@@ -439,11 +439,18 @@ func GenerateKeys() (encodedRequestPublicKey, encodedRequestPrivateKey, encodedO
 // The logger and logFieldFormatter callbacks are used to log errors and
 // metrics. The apiParameterValidator callback is used to validate client
 // API parameters submitted to the tactics request.
+//
+// The optional requestPublicKey, requestPrivateKey, and requestObfuscatedKey
+// base64 encoded string parameters may be used to specify and override the
+// corresponding Server config values.
 func NewServer(
 	logger common.Logger,
 	logFieldFormatter common.APIParameterLogFieldFormatter,
 	apiParameterValidator common.APIParameterValidator,
-	configFilename string) (*Server, error) {
+	configFilename string,
+	requestPublicKey string,
+	requestPrivateKey string,
+	requestObfuscatedKey string) (*Server, error) {
 
 	server := &Server{
 		logger:                logger,
@@ -464,6 +471,30 @@ func NewServer(
 				return errors.Trace(err)
 			}
 
+			if requestPublicKey != "" {
+				newServer.RequestPublicKey, err =
+					base64.StdEncoding.DecodeString(requestPublicKey)
+				if err != nil {
+					return errors.Trace(err)
+				}
+			}
+
+			if requestPrivateKey != "" {
+				newServer.RequestPrivateKey, err =
+					base64.StdEncoding.DecodeString(requestPrivateKey)
+				if err != nil {
+					return errors.Trace(err)
+				}
+			}
+
+			if requestObfuscatedKey != "" {
+				newServer.RequestObfuscatedKey, err =
+					base64.StdEncoding.DecodeString(requestObfuscatedKey)
+				if err != nil {
+					return errors.Trace(err)
+				}
+			}
+
 			err = newServer.Validate()
 			if err != nil {
 				return errors.Trace(err)

+ 13 - 8
psiphon/common/tactics/tactics_test.go

@@ -202,7 +202,10 @@ func TestTactics(t *testing.T) {
 		logger,
 		formatter,
 		validator,
-		configFileName)
+		configFileName,
+		"",
+		"",
+		"")
 	if err != nil {
 		t.Fatalf("NewServer failed: %s", err)
 	}
@@ -800,17 +803,16 @@ func TestTacticsFilterGeoIPScope(t *testing.T) {
 		t.Fatalf("GenerateKeys failed: %s", err)
 	}
 
-	tacticsConfigTemplate := fmt.Sprintf(`
+	// Exercise specifying keys in NewServer instead of config file.
+
+	tacticsConfigTemplate := `
     {
-      "RequestPublicKey" : "%s",
-      "RequestPrivateKey" : "%s",
-      "RequestObfuscatedKey" : "%s",
       "DefaultTactics" : {
         "TTL" : "60s"
       },
-      %%s
+      %s
     }
-    `, encodedRequestPublicKey, encodedRequestPrivateKey, encodedObfuscatedKey)
+    `
 
 	// Test: region-only scope
 
@@ -848,7 +850,10 @@ func TestTacticsFilterGeoIPScope(t *testing.T) {
 		nil,
 		nil,
 		nil,
-		configFileName)
+		configFileName,
+		encodedRequestPublicKey,
+		encodedRequestPrivateKey,
+		encodedObfuscatedKey)
 	if err != nil {
 		t.Fatalf("NewServer failed: %s", err)
 	}

+ 15 - 0
psiphon/server/config.go

@@ -432,6 +432,21 @@ type Config struct {
 	// tactics server configuration.
 	TacticsConfigFilename string `json:",omitempty"`
 
+	// TacticsRequestPublicKey is an optional, base64 encoded
+	// tactics.Server.RequestPublicKey which overrides the value in the
+	// tactics configuration file.
+	TacticsRequestPublicKey string `json:",omitempty"`
+
+	// TacticsRequestPrivateKey is an optional, base64 encoded
+	// tactics.Server.RequestPrivateKey which overrides the value in the
+	// tactics configuration file.
+	TacticsRequestPrivateKey string `json:",omitempty"`
+
+	// TacticsRequestObfuscatedKey is an optional, base64 encoded
+	// tactics.Server.RequestObfuscatedKey which overrides the value in the
+	// tactics configuration file.
+	TacticsRequestObfuscatedKey string `json:",omitempty"`
+
 	// BlocklistFilename is the path of a file containing a CSV-encoded
 	// blocklist configuration. See NewBlocklist for more file format
 	// documentation.

+ 1 - 4
psiphon/server/listener_test.go

@@ -86,10 +86,7 @@ func TestListener(t *testing.T) {
 	}
 
 	tacticsServer, err := tactics.NewServer(
-		nil,
-		nil,
-		nil,
-		tacticsConfigFilename)
+		nil, nil, nil, tacticsConfigFilename, "", "", "")
 	if err != nil {
 		t.Fatalf("NewServer failed: %s", err)
 	}

+ 1 - 1
psiphon/server/meek_test.go

@@ -560,7 +560,7 @@ func runTestMeekAccessControl(t *testing.T, rateLimit, restrictProvider, missing
 	}
 	mockSupport.GeoIPService, _ = NewGeoIPService([]string{})
 
-	tacticsServer, err := tactics.NewServer(nil, nil, nil, tacticsConfigFilename)
+	tacticsServer, err := tactics.NewServer(nil, nil, nil, tacticsConfigFilename, "", "", "")
 	if err != nil {
 		t.Fatalf("tactics.NewServer failed: %s", err)
 	}

+ 28 - 1
psiphon/server/server_test.go

@@ -879,7 +879,6 @@ func runServer(t *testing.T, runConfig *runServerConfig) {
 		runConfig.doLegacyDestinationBytes ||
 		runConfig.doTunneledDomainRequest
 
-	// All servers require a tactics config with valid keys.
 	tacticsRequestPublicKey, tacticsRequestPrivateKey, tacticsRequestObfuscatedKey, err :=
 		tactics.GenerateKeys()
 	if err != nil {
@@ -944,6 +943,21 @@ func runServer(t *testing.T, runConfig *runServerConfig) {
 		generateConfigParams.FrontingProviderID = prng.HexString(8)
 	}
 
+	var configTacticsRequestPublicKey, configTacticsRequestPrivateKey, configTacticsRequestObfuscatedKey string
+	if prng.FlipCoin() {
+
+		// Exercise specifying the tactics key parameters in the main server
+		// config file and not in the tactics config file.
+
+		configTacticsRequestPublicKey = tacticsRequestPublicKey
+		configTacticsRequestPrivateKey = tacticsRequestPrivateKey
+		configTacticsRequestObfuscatedKey = tacticsRequestObfuscatedKey
+
+		tacticsRequestPublicKey = ""
+		tacticsRequestPrivateKey = ""
+		tacticsRequestObfuscatedKey = ""
+	}
+
 	serverConfigJSON, _, _, _, encodedServerEntry, err := GenerateConfig(generateConfigParams)
 	if err != nil {
 		t.Fatalf("error generating server config: %s", err)
@@ -1046,6 +1060,19 @@ func runServer(t *testing.T, runConfig *runServerConfig) {
 	serverConfig["OSLConfigFilename"] = oslConfigFilename
 	if doServerTactics {
 		serverConfig["TacticsConfigFilename"] = tacticsConfigFilename
+
+		if configTacticsRequestPublicKey != "" {
+			serverConfig["TacticsRequestPublicKey"] = configTacticsRequestPublicKey
+
+		}
+		if configTacticsRequestPrivateKey != "" {
+			serverConfig["TacticsRequestPrivateKey"] = configTacticsRequestPrivateKey
+
+		}
+		if configTacticsRequestObfuscatedKey != "" {
+			serverConfig["TacticsRequestObfuscatedKey"] = configTacticsRequestObfuscatedKey
+
+		}
 	}
 	serverConfig["BlocklistFilename"] = blocklistFilename
 

+ 4 - 1
psiphon/server/services.go

@@ -621,7 +621,10 @@ func NewSupportServices(config *Config) (*SupportServices, error) {
 		CommonLogger(log),
 		getTacticsAPIParameterLogFieldFormatter(),
 		getTacticsAPIParameterValidator(config),
-		config.TacticsConfigFilename)
+		config.TacticsConfigFilename,
+		config.TacticsRequestPublicKey,
+		config.TacticsRequestPrivateKey,
+		config.TacticsRequestObfuscatedKey)
 	if err != nil {
 		return nil, errors.Trace(err)
 	}

+ 1 - 4
psiphon/server/tactics_test.go

@@ -142,10 +142,7 @@ func TestServerTacticsParametersCache(t *testing.T) {
 	}
 
 	tacticsServer, err := tactics.NewServer(
-		nil,
-		nil,
-		nil,
-		tacticsConfigFilename)
+		nil, nil, nil, tacticsConfigFilename, "", "", "")
 	if err != nil {
 		t.Fatalf("NewServer failed: %s", err)
 	}