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

Fix OSSH prefix parameter validation

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

+ 1 - 24
psiphon/common/obfuscator/obfuscator.go

@@ -31,7 +31,6 @@ import (
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
-	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/regen"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/transforms"
 	"golang.org/x/crypto/hkdf"
 )
@@ -655,33 +654,11 @@ func makeTerminator(keyword string, prefix []byte, direction string) ([]byte, er
 // with random bytes.
 func makePrefix(spec *OSSHPrefixSpec, keyword, direction string) ([]byte, error) {
 
-	if len(spec.Spec) != 1 || len(spec.Spec[0]) != 2 || spec.Spec[0][1] == "" {
-		return nil, errors.TraceNew("invalid prefix spec")
-	}
-
-	rng := prng.NewPRNGWithSeed(spec.Seed)
-
-	args := &regen.GeneratorArgs{
-		RngSource: rng,
-		ByteMode:  true,
-	}
-
-	gen, err := regen.NewGenerator(spec.Spec[0][1], args)
-	if err != nil {
-		return nil, errors.Trace(err)
-	}
-
-	prefix, err := gen.Generate()
+	prefix, err := spec.Spec.ApplyPrefix(spec.Seed, PREAMBLE_HEADER_LENGTH)
 	if err != nil {
 		return nil, errors.Trace(err)
 	}
 
-	if len(prefix) < PREAMBLE_HEADER_LENGTH {
-		// Add random padding to fill up to PREAMBLE_HEADER_LENGTH.
-		padding := rng.Bytes(PREAMBLE_HEADER_LENGTH - len(prefix))
-		prefix = append(prefix, padding...)
-	}
-
 	terminator, err := makeTerminator(keyword, prefix, direction)
 
 	if err != nil {

+ 5 - 1
psiphon/common/parameters/parameters.go

@@ -1117,7 +1117,11 @@ func (p *Parameters) Set(
 					return nil, errors.Trace(err)
 				}
 			case transforms.Specs:
-				err := v.Validate()
+				prefixMode := false
+				if name == OSSHPrefixSpecs || name == ServerOSSHPrefixSpecs {
+					prefixMode = true
+				}
+				err := v.Validate(prefixMode)
 				if err != nil {
 					if skipOnError {
 						continue

+ 54 - 4
psiphon/common/transforms/transforms.go

@@ -54,16 +54,29 @@ type Specs map[string]Spec
 
 // Validate checks that all entries in a set of Specs is well-formed, with
 // valid regular expressions.
-func (specs Specs) Validate() error {
+func (specs Specs) Validate(prefixMode bool) error {
 	seed, err := prng.NewSeed()
 	if err != nil {
 		return errors.Trace(err)
 	}
+
 	for _, spec := range specs {
+
 		// Call Apply to compile/validate the regular expressions and generators.
-		_, err := spec.ApplyString(seed, "")
-		if err != nil {
-			return errors.Trace(err)
+
+		if prefixMode {
+			if len(spec) != 1 || len(spec[0]) != 2 {
+				return errors.TraceNew("prefix mode requires exactly one transform")
+			}
+			_, err := spec.ApplyPrefix(seed, 0)
+			if err != nil {
+				return errors.Trace(err)
+			}
+		} else {
+			_, err := spec.ApplyString(seed, "")
+			if err != nil {
+				return errors.Trace(err)
+			}
 		}
 	}
 
@@ -142,6 +155,43 @@ func (specs Specs) Select(scope string, scopedSpecs ScopedSpecNames) (string, Sp
 	return specName, spec
 }
 
+// ApplyPrefix unlike other Apply methods, does not apply the Spec to an input.
+// It instead generates a sequence of bytes according to the Spec, and returns
+// at least minLength bytes if the Spec generates fewer than minLength bytes.
+//
+// The input seed is used for all random number generation. The same seed can be
+// supplied to produce the same output, for replay.
+func (spec Spec) ApplyPrefix(seed *prng.Seed, minLength int) ([]byte, error) {
+
+	if len(spec) != 1 || len(spec[0]) != 2 {
+		return nil, errors.TraceNew("prefix mode requires exactly one transform")
+	}
+
+	rng := prng.NewPRNGWithSeed(seed)
+
+	args := &regen.GeneratorArgs{
+		RngSource: rng,
+		ByteMode:  true,
+	}
+	gen, err := regen.NewGenerator(spec[0][1], args)
+	if err != nil {
+		return nil, errors.Trace(err)
+	}
+
+	prefix, err := gen.Generate()
+	if err != nil {
+		return nil, errors.Trace(err)
+	}
+
+	if len(prefix) < minLength {
+		// Add random padding to fill up to minLength.
+		padding := rng.Bytes(minLength - len(prefix))
+		prefix = append(prefix, padding...)
+	}
+
+	return prefix, nil
+}
+
 // ApplyString applies the Spec to the input string, producing the output string.
 //
 // The input seed is used for all random generation. The same seed can be