package util import ( stdtls "crypto/tls" "net" "testing" tls "github.com/refraction-networking/utls" ) func TestNewUTLSConfigPreservesClientSettings(t *testing.T) { called := false cfg := NewUTLSConfig(&stdtls.Config{ ServerName: "example.com", InsecureSkipVerify: true, NextProtos: []string{"h2", "http/1.1"}, MinVersion: stdtls.VersionTLS12, MaxVersion: stdtls.VersionTLS13, CipherSuites: []uint16{stdtls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, CurvePreferences: []stdtls.CurveID{stdtls.X25519, stdtls.CurveP256}, DynamicRecordSizingDisabled: true, Renegotiation: stdtls.RenegotiateOnceAsClient, VerifyConnection: func(state stdtls.ConnectionState) error { called = true if state.ServerName != "example.com" { t.Fatalf("ServerName = %q, want example.com", state.ServerName) } return nil }, }) if cfg.ServerName != "example.com" { t.Fatalf("ServerName = %q, want example.com", cfg.ServerName) } if !cfg.InsecureSkipVerify { t.Fatal("InsecureSkipVerify was not preserved") } if len(cfg.NextProtos) != 2 || cfg.NextProtos[0] != "h2" || cfg.NextProtos[1] != "http/1.1" { t.Fatalf("NextProtos = %v", cfg.NextProtos) } if cfg.MinVersion != tls.VersionTLS12 || cfg.MaxVersion != tls.VersionTLS13 { t.Fatalf("version range = %x-%x", cfg.MinVersion, cfg.MaxVersion) } if len(cfg.CipherSuites) != 1 || cfg.CipherSuites[0] != tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 { t.Fatalf("CipherSuites = %v", cfg.CipherSuites) } if len(cfg.CurvePreferences) != 2 || cfg.CurvePreferences[0] != tls.X25519 || cfg.CurvePreferences[1] != tls.CurveP256 { t.Fatalf("CurvePreferences = %v", cfg.CurvePreferences) } if !cfg.DynamicRecordSizingDisabled { t.Fatal("DynamicRecordSizingDisabled was not preserved") } if cfg.Renegotiation != tls.RenegotiateOnceAsClient { t.Fatalf("Renegotiation = %v", cfg.Renegotiation) } if cfg.VerifyConnection == nil { t.Fatal("VerifyConnection was not preserved") } if err := cfg.VerifyConnection(tls.ConnectionState{ServerName: "example.com"}); err != nil { t.Fatal(err) } if !called { t.Fatal("VerifyConnection wrapper was not called") } } func TestNewUTLSChromeClientBuildsChromeHello(t *testing.T) { c1, c2 := net.Pipe() defer c1.Close() defer c2.Close() client := NewUTLSChromeClient(c1, &stdtls.Config{ServerName: "example.com"}) if client.ClientHelloID != tls.HelloChrome_Auto { t.Fatalf("ClientHelloID = %+v, want %+v", client.ClientHelloID, tls.HelloChrome_Auto) } if err := client.BuildHandshakeStateWithoutSession(); err != nil { t.Fatal(err) } if len(client.Extensions) == 0 { t.Fatal("Chrome ClientHello has no extensions") } } func TestNewUTLSWebSocketClientAppliesCustomSpec(t *testing.T) { c1, c2 := net.Pipe() defer c1.Close() defer c2.Close() client, err := NewUTLSWebSocketClient(c1, &stdtls.Config{ ServerName: "example.com", NextProtos: []string{"h2"}, MinVersion: stdtls.VersionTLS13, }, false) if err != nil { t.Fatal(err) } if client.ClientHelloID != tls.HelloCustom { t.Fatalf("ClientHelloID = %+v, want %+v", client.ClientHelloID, tls.HelloCustom) } if len(client.Extensions) == 0 { t.Fatal("custom WebSocket ClientHello preset has no extensions") } if err := client.BuildHandshakeStateWithoutSession(); err != nil { t.Fatal(err) } if len(client.HandshakeState.Hello.AlpnProtocols) != 1 || client.HandshakeState.Hello.AlpnProtocols[0] != "http/1.1" { t.Fatalf("ALPN = %v, want [http/1.1]", client.HandshakeState.Hello.AlpnProtocols) } }