github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/tlsDialer_test.go (about)

     1  /*
     2   * Copyright (c) 2019, Psiphon Inc.
     3   * All rights reserved.
     4   *
     5   * This program is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU General Public License as published by
     7   * the Free Software Foundation, either version 3 of the License, or
     8   * (at your option) any later version.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package psiphon
    21  
    22  import (
    23  	"context"
    24  	"crypto/rand"
    25  	"crypto/rsa"
    26  	"crypto/sha256"
    27  	"crypto/tls"
    28  	"crypto/x509"
    29  	"crypto/x509/pkix"
    30  	"encoding/base64"
    31  	"encoding/json"
    32  	"encoding/pem"
    33  	"fmt"
    34  	"io/ioutil"
    35  	"math/big"
    36  	"net"
    37  	"net/http"
    38  	"os"
    39  	"path/filepath"
    40  	"strings"
    41  	"sync"
    42  	"testing"
    43  	"time"
    44  
    45  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
    46  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
    47  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
    48  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values"
    49  	tris "github.com/Psiphon-Labs/tls-tris"
    50  	utls "github.com/Psiphon-Labs/utls"
    51  )
    52  
    53  func TestTLSCertificateVerification(t *testing.T) {
    54  
    55  	testDataDirName, err := ioutil.TempDir("", "psiphon-tls-certificate-verification-test")
    56  	if err != nil {
    57  		t.Fatalf("TempDir failed: %v", err)
    58  	}
    59  	defer os.RemoveAll(testDataDirName)
    60  
    61  	serverName := "example.org"
    62  
    63  	rootCAsFileName,
    64  		rootCACertificatePin,
    65  		serverCertificatePin,
    66  		shutdown,
    67  		serverAddr,
    68  		dialer := initTestCertificatesAndWebServer(
    69  		t, testDataDirName, serverName)
    70  	defer shutdown()
    71  
    72  	// Test: without custom RootCAs, the TLS dial fails.
    73  
    74  	params, err := parameters.NewParameters(nil)
    75  	if err != nil {
    76  		t.Fatalf("parameters.NewParameters failed: %v", err)
    77  	}
    78  
    79  	conn, err := CustomTLSDial(
    80  		context.Background(), "tcp", serverAddr,
    81  		&CustomTLSConfig{
    82  			Parameters: params,
    83  			Dial:       dialer,
    84  		})
    85  
    86  	if err == nil {
    87  		conn.Close()
    88  		t.Errorf("unexpected success without custom RootCAs")
    89  	}
    90  
    91  	// Test: without custom RootCAs and with SkipVerify, the TLS dial succeeds.
    92  
    93  	conn, err = CustomTLSDial(
    94  		context.Background(), "tcp", serverAddr,
    95  		&CustomTLSConfig{
    96  			Parameters: params,
    97  			Dial:       dialer,
    98  			SkipVerify: true,
    99  		})
   100  
   101  	if err != nil {
   102  		t.Errorf("CustomTLSDial failed: %v", err)
   103  	} else {
   104  		conn.Close()
   105  	}
   106  
   107  	// Test: with custom RootCAs, the TLS dial succeeds.
   108  
   109  	conn, err = CustomTLSDial(
   110  		context.Background(), "tcp", serverAddr,
   111  		&CustomTLSConfig{
   112  			Parameters:                    params,
   113  			Dial:                          dialer,
   114  			TrustedCACertificatesFilename: rootCAsFileName,
   115  		})
   116  
   117  	if err != nil {
   118  		t.Errorf("CustomTLSDial failed: %v", err)
   119  	} else {
   120  		conn.Close()
   121  	}
   122  
   123  	// Test: with SNI changed and VerifyServerName set, the TLS dial succeeds.
   124  
   125  	conn, err = CustomTLSDial(
   126  		context.Background(), "tcp", serverAddr,
   127  		&CustomTLSConfig{
   128  			Parameters:                    params,
   129  			Dial:                          dialer,
   130  			SNIServerName:                 "not-" + serverName,
   131  			VerifyServerName:              serverName,
   132  			TrustedCACertificatesFilename: rootCAsFileName,
   133  		})
   134  
   135  	if err != nil {
   136  		t.Errorf("CustomTLSDial failed: %v", err)
   137  	} else {
   138  		conn.Close()
   139  	}
   140  
   141  	// Test: with an invalid pin, the TLS dial fails.
   142  
   143  	invalidPin := base64.StdEncoding.EncodeToString(make([]byte, 32))
   144  
   145  	conn, err = CustomTLSDial(
   146  		context.Background(), "tcp", serverAddr,
   147  		&CustomTLSConfig{
   148  			Parameters:                    params,
   149  			Dial:                          dialer,
   150  			VerifyPins:                    []string{invalidPin},
   151  			TrustedCACertificatesFilename: rootCAsFileName,
   152  		})
   153  
   154  	if err == nil {
   155  		conn.Close()
   156  		t.Errorf("unexpected success without invalid pin")
   157  	}
   158  
   159  	// Test: with the root CA certirficate pinned, the TLS dial succeeds.
   160  
   161  	conn, err = CustomTLSDial(
   162  		context.Background(), "tcp", serverAddr,
   163  		&CustomTLSConfig{
   164  			Parameters:                    params,
   165  			Dial:                          dialer,
   166  			VerifyPins:                    []string{rootCACertificatePin},
   167  			TrustedCACertificatesFilename: rootCAsFileName,
   168  		})
   169  
   170  	if err != nil {
   171  		t.Errorf("CustomTLSDial failed: %v", err)
   172  	} else {
   173  		conn.Close()
   174  	}
   175  
   176  	// Test: with the server certificate pinned, the TLS dial succeeds.
   177  
   178  	conn, err = CustomTLSDial(
   179  		context.Background(), "tcp", serverAddr,
   180  		&CustomTLSConfig{
   181  			Parameters:                    params,
   182  			Dial:                          dialer,
   183  			VerifyPins:                    []string{serverCertificatePin},
   184  			TrustedCACertificatesFilename: rootCAsFileName,
   185  		})
   186  
   187  	if err != nil {
   188  		t.Errorf("CustomTLSDial failed: %v", err)
   189  	} else {
   190  		conn.Close()
   191  	}
   192  
   193  	// Test: with SNI changed, VerifyServerName set, and pinning the TLS dial
   194  	// succeeds.
   195  
   196  	conn, err = CustomTLSDial(
   197  		context.Background(), "tcp", serverAddr,
   198  		&CustomTLSConfig{
   199  			Parameters:                    params,
   200  			Dial:                          dialer,
   201  			SNIServerName:                 "not-" + serverName,
   202  			VerifyServerName:              serverName,
   203  			VerifyPins:                    []string{rootCACertificatePin},
   204  			TrustedCACertificatesFilename: rootCAsFileName,
   205  		})
   206  
   207  	if err != nil {
   208  		t.Errorf("CustomTLSDial failed: %v", err)
   209  	} else {
   210  		conn.Close()
   211  	}
   212  }
   213  
   214  // initTestCertificatesAndWebServer creates a Root CA, a web server
   215  // certificate, for serverName, signed by that Root CA, and runs a web server
   216  // that uses that server certificate. initRootCAandWebServer returns:
   217  //
   218  // - the file name containing the Root CA, to be used with
   219  //   CustomTLSConfig.TrustedCACertificatesFilename
   220  //
   221  // - pin values for the Root CA and server certificare, to be used with
   222  //   CustomTLSConfig.VerifyPins
   223  //
   224  // - a shutdown function which the caller must invoked to terminate the web
   225  //   server
   226  //
   227  // - the web server dial address: serverName and port
   228  //
   229  // - and a dialer function, which bypasses DNS resolution of serverName, to be
   230  //   used with CustomTLSConfig.Dial
   231  func initTestCertificatesAndWebServer(
   232  	t *testing.T,
   233  	testDataDirName string,
   234  	serverName string) (string, string, string, func(), string, common.Dialer) {
   235  
   236  	// Generate a root CA certificate.
   237  
   238  	rootCACertificate := &x509.Certificate{
   239  		SerialNumber: big.NewInt(1),
   240  		Subject: pkix.Name{
   241  			Organization: []string{"test"},
   242  		},
   243  		NotBefore:             time.Now(),
   244  		NotAfter:              time.Now().AddDate(1, 0, 0),
   245  		IsCA:                  true,
   246  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   247  		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
   248  		BasicConstraintsValid: true,
   249  	}
   250  
   251  	rootCAPrivateKey, err := rsa.GenerateKey(rand.Reader, 4096)
   252  	if err != nil {
   253  		t.Fatalf("rsa.GenerateKey failed: %v", err)
   254  	}
   255  
   256  	rootCACertificateBytes, err := x509.CreateCertificate(
   257  		rand.Reader,
   258  		rootCACertificate,
   259  		rootCACertificate,
   260  		&rootCAPrivateKey.PublicKey,
   261  		rootCAPrivateKey)
   262  	if err != nil {
   263  		t.Fatalf("x509.CreateCertificate failed: %v", err)
   264  	}
   265  
   266  	pemRootCACertificate := pem.EncodeToMemory(
   267  		&pem.Block{
   268  			Type:  "CERTIFICATE",
   269  			Bytes: rootCACertificateBytes,
   270  		})
   271  
   272  	// Generate a server certificate.
   273  
   274  	serverCertificate := &x509.Certificate{
   275  		SerialNumber: big.NewInt(2),
   276  		Subject: pkix.Name{
   277  			Organization: []string{"test"},
   278  		},
   279  		DNSNames:    []string{serverName},
   280  		NotBefore:   time.Now(),
   281  		NotAfter:    time.Now().AddDate(1, 0, 0),
   282  		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   283  		KeyUsage:    x509.KeyUsageDigitalSignature,
   284  	}
   285  
   286  	serverPrivateKey, err := rsa.GenerateKey(rand.Reader, 4096)
   287  	if err != nil {
   288  		t.Fatalf("rsa.GenerateKey failed: %v", err)
   289  	}
   290  
   291  	serverCertificateBytes, err := x509.CreateCertificate(
   292  		rand.Reader,
   293  		serverCertificate,
   294  		rootCACertificate,
   295  		&serverPrivateKey.PublicKey,
   296  		rootCAPrivateKey)
   297  	if err != nil {
   298  		t.Fatalf("x509.CreateCertificate failed: %v", err)
   299  	}
   300  
   301  	pemServerCertificate := pem.EncodeToMemory(
   302  		&pem.Block{
   303  			Type:  "CERTIFICATE",
   304  			Bytes: serverCertificateBytes,
   305  		})
   306  
   307  	pemServerPrivateKey := pem.EncodeToMemory(
   308  		&pem.Block{
   309  			Type:  "RSA PRIVATE KEY",
   310  			Bytes: x509.MarshalPKCS1PrivateKey(serverPrivateKey),
   311  		})
   312  
   313  	// Pave Root CA file.
   314  
   315  	rootCAsFileName := filepath.Join(testDataDirName, "RootCAs.pem")
   316  	err = ioutil.WriteFile(rootCAsFileName, pemRootCACertificate, 0600)
   317  	if err != nil {
   318  		t.Fatalf("WriteFile failed: %v", err)
   319  	}
   320  
   321  	// Calculate certificate pins.
   322  
   323  	parsedCertificate, err := x509.ParseCertificate(rootCACertificateBytes)
   324  	if err != nil {
   325  		t.Fatalf("x509.ParseCertificate failed: %v", err)
   326  	}
   327  	publicKeyDigest := sha256.Sum256(parsedCertificate.RawSubjectPublicKeyInfo)
   328  	rootCACertificatePin := base64.StdEncoding.EncodeToString(publicKeyDigest[:])
   329  
   330  	parsedCertificate, err = x509.ParseCertificate(serverCertificateBytes)
   331  	if err != nil {
   332  		t.Fatalf("x509.ParseCertificate failed: %v", err)
   333  	}
   334  	publicKeyDigest = sha256.Sum256(parsedCertificate.RawSubjectPublicKeyInfo)
   335  	serverCertificatePin := base64.StdEncoding.EncodeToString(publicKeyDigest[:])
   336  
   337  	// Run an HTTPS server with the server certificate.
   338  
   339  	serverKeyPair, err := tls.X509KeyPair(
   340  		pemServerCertificate, pemServerPrivateKey)
   341  	if err != nil {
   342  		t.Fatalf("tls.X509KeyPair failed: %v", err)
   343  	}
   344  
   345  	mux := http.NewServeMux()
   346  	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
   347  		w.Write([]byte("test"))
   348  	})
   349  
   350  	server := &http.Server{
   351  		Handler: mux,
   352  	}
   353  
   354  	listener, err := net.Listen("tcp", "127.0.0.1:0")
   355  	if err != nil {
   356  		t.Fatalf("net.Listen failed: %v", err)
   357  	}
   358  	dialAddr := listener.Addr().String()
   359  	_, port, _ := net.SplitHostPort(dialAddr)
   360  	serverAddr := fmt.Sprintf("%s:%s", serverName, port)
   361  
   362  	listener = tls.NewListener(
   363  		listener,
   364  		&tls.Config{
   365  			Certificates: []tls.Certificate{serverKeyPair},
   366  		})
   367  
   368  	var wg sync.WaitGroup
   369  	wg.Add(1)
   370  	go func() {
   371  		wg.Done()
   372  		server.Serve(listener)
   373  	}()
   374  
   375  	shutdown := func() {
   376  		listener.Close()
   377  		server.Shutdown(context.Background())
   378  		wg.Wait()
   379  	}
   380  
   381  	// Initialize a custom dialer for the client which bypasses DNS resolution.
   382  
   383  	dialer := func(ctx context.Context, network, address string) (net.Conn, error) {
   384  		d := &net.Dialer{}
   385  		// Ignore the address input, which will be serverAddr, and dial dialAddr, as
   386  		// if the serverName in serverAddr had been resolved to "127.0.0.1".
   387  		return d.DialContext(ctx, network, dialAddr)
   388  	}
   389  
   390  	return rootCAsFileName,
   391  		rootCACertificatePin,
   392  		serverCertificatePin,
   393  		shutdown,
   394  		serverAddr,
   395  		dialer
   396  }
   397  
   398  func TestTLSDialerCompatibility(t *testing.T) {
   399  
   400  	// This test checks that each TLS profile can successfully complete a TLS
   401  	// handshake with various servers. By default, only the "psiphon" case is
   402  	// run, which runs the same TLS listener used by a Psiphon server.
   403  	//
   404  	// An optional config file, when supplied, enables testing against remote
   405  	// servers. Config should be newline delimited list of domain/IP:port TLS
   406  	// host addresses to connect to.
   407  
   408  	var configAddresses []string
   409  	config, err := ioutil.ReadFile("tlsDialerCompatibility_test.config")
   410  	if err == nil {
   411  		configAddresses = strings.Split(string(config), "\n")
   412  	}
   413  
   414  	runner := func(address string) func(t *testing.T) {
   415  		return func(t *testing.T) {
   416  			testTLSDialerCompatibility(t, address)
   417  		}
   418  	}
   419  
   420  	for _, address := range configAddresses {
   421  		if len(address) > 0 {
   422  			t.Run(address, runner(address))
   423  		}
   424  	}
   425  
   426  	t.Run("psiphon", runner(""))
   427  }
   428  
   429  func testTLSDialerCompatibility(t *testing.T, address string) {
   430  
   431  	if address == "" {
   432  
   433  		// Same tls-tris config as psiphon/server/meek.go
   434  
   435  		certificate, privateKey, err := common.GenerateWebServerCertificate(values.GetHostName())
   436  		if err != nil {
   437  			t.Fatalf("common.GenerateWebServerCertificate failed: %v", err)
   438  		}
   439  
   440  		tlsCertificate, err := tris.X509KeyPair([]byte(certificate), []byte(privateKey))
   441  		if err != nil {
   442  			t.Fatalf("tris.X509KeyPair failed: %v", err)
   443  		}
   444  
   445  		config := &tris.Config{
   446  			Certificates:            []tris.Certificate{tlsCertificate},
   447  			NextProtos:              []string{"http/1.1"},
   448  			MinVersion:              tris.VersionTLS10,
   449  			UseExtendedMasterSecret: true,
   450  		}
   451  
   452  		tcpListener, err := net.Listen("tcp", "127.0.0.1:0")
   453  		if err != nil {
   454  			t.Fatalf("net.Listen failed: %v", err)
   455  		}
   456  
   457  		tlsListener := tris.NewListener(tcpListener, config)
   458  		defer tlsListener.Close()
   459  
   460  		address = tlsListener.Addr().String()
   461  
   462  		go func() {
   463  			for {
   464  				conn, err := tlsListener.Accept()
   465  				if err != nil {
   466  					return
   467  				}
   468  				err = conn.(*tris.Conn).Handshake()
   469  				if err != nil {
   470  					t.Logf("tris.Conn.Handshake failed: %v", err)
   471  				}
   472  				conn.Close()
   473  			}
   474  		}()
   475  	}
   476  
   477  	dialer := func(ctx context.Context, network, address string) (net.Conn, error) {
   478  		d := &net.Dialer{}
   479  		return d.DialContext(ctx, network, address)
   480  	}
   481  
   482  	params := makeCustomTLSProfilesParameters(t, false, "")
   483  
   484  	profiles := append([]string(nil), protocol.SupportedTLSProfiles...)
   485  	profiles = append(profiles, params.Get().CustomTLSProfileNames()...)
   486  
   487  	for _, tlsProfile := range profiles {
   488  
   489  		repeats := 2
   490  		if protocol.TLSProfileIsRandomized(tlsProfile) {
   491  			repeats = 20
   492  		}
   493  
   494  		success := 0
   495  		tlsVersions := []string{}
   496  		for i := 0; i < repeats; i++ {
   497  
   498  			transformHostname := i%2 == 0
   499  
   500  			tlsConfig := &CustomTLSConfig{
   501  				Parameters: params,
   502  				Dial:       dialer,
   503  				SkipVerify: true,
   504  				TLSProfile: tlsProfile,
   505  			}
   506  
   507  			if transformHostname {
   508  				tlsConfig.SNIServerName = values.GetHostName()
   509  			} else {
   510  				tlsConfig.UseDialAddrSNI = true
   511  			}
   512  
   513  			ctx, cancelFunc := context.WithTimeout(context.Background(), 5*time.Second)
   514  
   515  			conn, err := CustomTLSDial(ctx, "tcp", address, tlsConfig)
   516  
   517  			if err != nil {
   518  				t.Logf("CustomTLSDial failed: %s (transformHostname: %v): %v",
   519  					tlsProfile, transformHostname, err)
   520  			} else {
   521  
   522  				tlsVersion := ""
   523  				version := conn.(*utls.UConn).ConnectionState().Version
   524  				if version == utls.VersionTLS12 {
   525  					tlsVersion = "TLS 1.2"
   526  				} else if version == utls.VersionTLS13 {
   527  					tlsVersion = "TLS 1.3"
   528  				} else {
   529  					t.Fatalf("Unexpected TLS version: %v", version)
   530  				}
   531  				if !common.Contains(tlsVersions, tlsVersion) {
   532  					tlsVersions = append(tlsVersions, tlsVersion)
   533  				}
   534  
   535  				conn.Close()
   536  				success += 1
   537  			}
   538  
   539  			cancelFunc()
   540  
   541  			time.Sleep(100 * time.Millisecond)
   542  		}
   543  
   544  		result := fmt.Sprintf(
   545  			"%s: %d/%d successful; negotiated TLS versions: %v",
   546  			tlsProfile, success, repeats, tlsVersions)
   547  
   548  		if success == repeats {
   549  			t.Logf(result)
   550  		} else {
   551  			t.Errorf(result)
   552  		}
   553  	}
   554  }
   555  
   556  func TestSelectTLSProfile(t *testing.T) {
   557  
   558  	params := makeCustomTLSProfilesParameters(t, false, "")
   559  
   560  	profiles := append([]string(nil), protocol.SupportedTLSProfiles...)
   561  	profiles = append(profiles, params.Get().CustomTLSProfileNames()...)
   562  
   563  	selected := make(map[string]int)
   564  
   565  	numSelections := 10000
   566  
   567  	for i := 0; i < numSelections; i++ {
   568  		profile := SelectTLSProfile(false, false, "", params.Get())
   569  		selected[profile] += 1
   570  	}
   571  
   572  	// All TLS profiles should be selected at least once.
   573  
   574  	for _, profile := range profiles {
   575  		if selected[profile] < 1 {
   576  			t.Errorf("TLS profile %s not selected", profile)
   577  		}
   578  	}
   579  
   580  	// Only expected profiles should be selected
   581  
   582  	if len(selected) != len(profiles) {
   583  		t.Errorf("unexpected TLS profile selected")
   584  	}
   585  
   586  	// Randomized TLS profiles should be selected with expected probability.
   587  
   588  	numRandomized := 0
   589  	for profile, n := range selected {
   590  		if protocol.TLSProfileIsRandomized(profile) {
   591  			numRandomized += n
   592  		}
   593  	}
   594  
   595  	t.Logf("ratio of randomized selected: %d/%d",
   596  		numRandomized, numSelections)
   597  
   598  	randomizedProbability := params.Get().Float(
   599  		parameters.SelectRandomizedTLSProfileProbability)
   600  
   601  	if numRandomized < int(0.9*float64(numSelections)*randomizedProbability) ||
   602  		numRandomized > int(1.1*float64(numSelections)*randomizedProbability) {
   603  
   604  		t.Error("Unexpected ratio")
   605  	}
   606  
   607  	// getUTLSClientHelloID should map each TLS profile to a utls ClientHelloID.
   608  
   609  	for i, profile := range profiles {
   610  		utlsClientHelloID, utlsClientHelloSpec, err :=
   611  			getUTLSClientHelloID(params.Get(), profile)
   612  		if err != nil {
   613  			t.Fatalf("getUTLSClientHelloID failed: %v", err)
   614  		}
   615  
   616  		var unexpectedClientHelloID, unexpectedClientHelloSpec bool
   617  		if i < len(protocol.SupportedTLSProfiles) {
   618  			if utlsClientHelloID == utls.HelloCustom {
   619  				unexpectedClientHelloID = true
   620  			}
   621  			if utlsClientHelloSpec != nil {
   622  				unexpectedClientHelloSpec = true
   623  			}
   624  		} else {
   625  			if utlsClientHelloID != utls.HelloCustom {
   626  				unexpectedClientHelloID = true
   627  			}
   628  			if utlsClientHelloSpec == nil {
   629  				unexpectedClientHelloSpec = true
   630  			}
   631  		}
   632  
   633  		if unexpectedClientHelloID {
   634  			t.Errorf("Unexpected ClientHelloID for TLS profile %s", profile)
   635  		}
   636  		if unexpectedClientHelloSpec {
   637  			t.Errorf("Unexpected ClientHelloSpec for TLS profile %s", profile)
   638  		}
   639  	}
   640  
   641  	// Only custom TLS profiles should be selected
   642  
   643  	params = makeCustomTLSProfilesParameters(t, true, "")
   644  	customTLSProfileNames := params.Get().CustomTLSProfileNames()
   645  
   646  	for i := 0; i < numSelections; i++ {
   647  		profile := SelectTLSProfile(false, false, "", params.Get())
   648  		if !common.Contains(customTLSProfileNames, profile) {
   649  			t.Errorf("unexpected non-custom TLS profile selected")
   650  		}
   651  	}
   652  
   653  	// Disabled TLS profiles should not be selected
   654  
   655  	frontingProviderID := "frontingProviderID"
   656  
   657  	params = makeCustomTLSProfilesParameters(t, false, frontingProviderID)
   658  	disableTLSProfiles := params.Get().LabeledTLSProfiles(
   659  		parameters.DisableFrontingProviderTLSProfiles, frontingProviderID)
   660  
   661  	if len(disableTLSProfiles) < 1 {
   662  		t.Errorf("unexpected disabled TLS profiles count")
   663  	}
   664  
   665  	for i := 0; i < numSelections; i++ {
   666  		profile := SelectTLSProfile(false, true, frontingProviderID, params.Get())
   667  		if common.Contains(disableTLSProfiles, profile) {
   668  			t.Errorf("unexpected disabled TLS profile selected")
   669  		}
   670  	}
   671  
   672  	// Session ticket incapable TLS 1.2 profiles should not be selected
   673  
   674  	for i := 0; i < numSelections; i++ {
   675  		profile := SelectTLSProfile(true, false, "", params.Get())
   676  		if protocol.TLS12ProfileOmitsSessionTickets(profile) {
   677  			t.Errorf("unexpected session ticket incapable TLS profile selected")
   678  		}
   679  	}
   680  }
   681  
   682  func BenchmarkRandomizedGetClientHelloVersion(b *testing.B) {
   683  	for n := 0; n < b.N; n++ {
   684  		utlsClientHelloID := utls.HelloRandomized
   685  		utlsClientHelloID.Seed, _ = utls.NewPRNGSeed()
   686  		getClientHelloVersion(utlsClientHelloID, nil)
   687  	}
   688  }
   689  
   690  func makeCustomTLSProfilesParameters(
   691  	t *testing.T, useOnlyCustomTLSProfiles bool, frontingProviderID string) *parameters.Parameters {
   692  
   693  	params, err := parameters.NewParameters(nil)
   694  	if err != nil {
   695  		t.Fatalf("NewParameters failed: %v", err)
   696  	}
   697  
   698  	// Equivilent to utls.HelloChrome_62
   699  	customTLSProfilesJSON := []byte(`
   700      [
   701        {
   702          "Name": "CustomProfile",
   703          "UTLSSpec": {
   704            "TLSVersMax": 771,
   705            "TLSVersMin": 769,
   706            "CipherSuites": [2570, 49195, 49199, 49196, 49200, 52393, 52392, 49171, 49172, 156, 157, 47, 53, 10],
   707            "CompressionMethods": [0],
   708            "Extensions" : [
   709              {"Name": "GREASE"},
   710              {"Name": "SNI"},
   711              {"Name": "ExtendedMasterSecret"},
   712              {"Name": "SessionTicket"},
   713              {"Name": "SignatureAlgorithms", "Data": {"SupportedSignatureAlgorithms": [1027, 2052, 1025, 1283, 2053, 1281, 2054, 1537, 513]}},
   714              {"Name": "StatusRequest"},
   715              {"Name": "SCT"},
   716              {"Name": "ALPN", "Data": {"AlpnProtocols": ["h2", "http/1.1"]}},
   717              {"Name": "ChannelID"},
   718              {"Name": "SupportedPoints", "Data": {"SupportedPoints": [0]}},
   719              {"Name": "SupportedCurves", "Data": {"Curves": [2570, 29, 23, 24]}},
   720              {"Name": "BoringPadding"},
   721              {"Name": "GREASE"}],
   722            "GetSessionID": "SHA-256"
   723          }
   724        }
   725      ]`)
   726  
   727  	var customTLSProfiles protocol.CustomTLSProfiles
   728  
   729  	err = json.Unmarshal(customTLSProfilesJSON, &customTLSProfiles)
   730  	if err != nil {
   731  		t.Fatalf("Unmarshal failed: %v", err)
   732  	}
   733  
   734  	applyParameters := make(map[string]interface{})
   735  
   736  	applyParameters[parameters.UseOnlyCustomTLSProfiles] = useOnlyCustomTLSProfiles
   737  	applyParameters[parameters.CustomTLSProfiles] = customTLSProfiles
   738  
   739  	if frontingProviderID != "" {
   740  		tlsProfiles := make(protocol.TLSProfiles, 0)
   741  		tlsProfiles = append(tlsProfiles, "CustomProfile")
   742  		for i, tlsProfile := range protocol.SupportedTLSProfiles {
   743  			if i%2 == 0 {
   744  				tlsProfiles = append(tlsProfiles, tlsProfile)
   745  			}
   746  		}
   747  		disabledTLSProfiles := make(protocol.LabeledTLSProfiles)
   748  		disabledTLSProfiles[frontingProviderID] = tlsProfiles
   749  
   750  		applyParameters[parameters.DisableFrontingProviderTLSProfiles] = disabledTLSProfiles
   751  	}
   752  
   753  	_, err = params.Set("", false, applyParameters)
   754  	if err != nil {
   755  		t.Fatalf("Set failed: %v", err)
   756  	}
   757  
   758  	customTLSProfileNames := params.Get().CustomTLSProfileNames()
   759  	if len(customTLSProfileNames) != 1 {
   760  		t.Fatalf("Unexpected CustomTLSProfileNames count")
   761  	}
   762  
   763  	return params
   764  }