github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/protocol/customTLSProfiles_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 protocol
    21  
    22  import (
    23  	"bytes"
    24  	"crypto/sha256"
    25  	"encoding/json"
    26  	"testing"
    27  
    28  	utls "github.com/Psiphon-Labs/utls"
    29  )
    30  
    31  func TestCustomTLSProfiles(t *testing.T) {
    32  
    33  	// Based on utls.HelloChrome_62. Some attributes have been removed to
    34  	// eliminate randomness; and additional extensions have been added for extra
    35  	// test coverage.
    36  
    37  	utlsClientHelloSpec := &utls.ClientHelloSpec{
    38  		TLSVersMax: utls.VersionTLS12,
    39  		TLSVersMin: utls.VersionTLS10,
    40  		CipherSuites: []uint16{
    41  			utls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
    42  			utls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
    43  			utls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
    44  			utls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
    45  			utls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
    46  			utls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
    47  			utls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
    48  			utls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
    49  			utls.TLS_RSA_WITH_AES_128_GCM_SHA256,
    50  			utls.TLS_RSA_WITH_AES_256_GCM_SHA384,
    51  			utls.TLS_RSA_WITH_AES_128_CBC_SHA,
    52  			utls.TLS_RSA_WITH_AES_256_CBC_SHA,
    53  			utls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
    54  		},
    55  		CompressionMethods: []byte{0},
    56  		Extensions: []utls.TLSExtension{
    57  			&utls.RenegotiationInfoExtension{Renegotiation: utls.RenegotiateOnceAsClient},
    58  			&utls.SNIExtension{},
    59  			&utls.UtlsExtendedMasterSecretExtension{},
    60  			&utls.SessionTicketExtension{},
    61  			&utls.SignatureAlgorithmsExtension{SupportedSignatureAlgorithms: []utls.SignatureScheme{
    62  				utls.ECDSAWithP256AndSHA256,
    63  				utls.PSSWithSHA256,
    64  				utls.PKCS1WithSHA256,
    65  				utls.ECDSAWithP384AndSHA384,
    66  				utls.PSSWithSHA384,
    67  				utls.PKCS1WithSHA384,
    68  				utls.PSSWithSHA512,
    69  				utls.PKCS1WithSHA512,
    70  				utls.PKCS1WithSHA1},
    71  			},
    72  			&utls.StatusRequestExtension{},
    73  			&utls.SCTExtension{},
    74  			&utls.ALPNExtension{AlpnProtocols: []string{"h2", "http/1.1"}},
    75  			&utls.FakeChannelIDExtension{},
    76  			&utls.SupportedPointsExtension{SupportedPoints: []byte{0}},
    77  			&utls.SupportedCurvesExtension{[]utls.CurveID{
    78  				utls.X25519, utls.CurveP256, utls.CurveP384}},
    79  			&utls.UtlsPaddingExtension{GetPaddingLen: utls.BoringPaddingStyle},
    80  
    81  			// Additional extensions for test coverage
    82  			&utls.NPNExtension{NextProtos: []string{"http/1.1"}},
    83  			&utls.GenericExtension{Id: 9999, Data: []byte("generic extension")},
    84  			&utls.KeyShareExtension{[]utls.KeyShare{
    85  				{Group: utls.X25519, Data: []byte{9, 9, 9, 9}},
    86  			}},
    87  			&utls.PSKKeyExchangeModesExtension{[]uint8{
    88  				utls.PskModeDHE,
    89  			}},
    90  			&utls.SupportedVersionsExtension{[]uint16{
    91  				utls.VersionTLS13,
    92  				utls.VersionTLS12,
    93  				utls.VersionTLS11,
    94  				utls.VersionTLS10,
    95  			}},
    96  			&utls.UtlsCompressCertExtension{[]utls.CertCompressionAlgo{
    97  				utls.CertCompressionBrotli,
    98  			}},
    99  			&utls.FakeChannelIDExtension{},
   100  			&utls.FakeRecordSizeLimitExtension{Limit: 9999},
   101  		},
   102  		GetSessionID: sha256.Sum256,
   103  	}
   104  
   105  	customTLSProfilesJSON := []byte(`
   106      [
   107        {
   108          "Name": "CustomProfile",
   109          "UTLSSpec": {
   110            "TLSVersMax": 771,
   111            "TLSVersMin": 769,
   112            "CipherSuites": [49195, 49199, 49196, 49200, 52393, 52392, 49171, 49172, 156, 157, 47, 53, 10],
   113            "CompressionMethods": [0],
   114            "Extensions" : [
   115              {"Name": "RenegotiationInfo", "Data": {"Renegotiation": 1}},
   116              {"Name": "SNI"},
   117              {"Name": "ExtendedMasterSecret"},
   118              {"Name": "SessionTicket"},
   119              {"Name": "SignatureAlgorithms", "Data": {"SupportedSignatureAlgorithms": [1027, 2052, 1025, 1283, 2053, 1281, 2054, 1537, 513]}},
   120              {"Name": "StatusRequest"},
   121              {"Name": "SCT"},
   122              {"Name": "ALPN", "Data": {"AlpnProtocols": ["h2", "http/1.1"]}},
   123              {"Name": "ChannelID"},
   124              {"Name": "SupportedPoints", "Data": {"SupportedPoints": [0]}},
   125              {"Name": "SupportedCurves", "Data": {"Curves": [29, 23, 24]}},
   126              {"Name": "BoringPadding"},
   127              {"Name": "NPN", "Data": {"NextProtos": ["h2", "http/1.1"]}},
   128              {"Name": "Generic", "Data": {"Id": 9999, "Data": [103, 101, 110, 101, 114, 105, 99, 32, 101, 120, 116, 101, 110, 115, 105, 111, 110]}},
   129              {"Name": "KeyShare", "Data": {"KeyShares": [{"Group": 29, "Data": [9, 9, 9, 9]}]}},
   130              {"Name": "PSKKeyExchangeModes", "Data": {"Modes": [1]}},
   131              {"Name": "SupportedVersions", "Data": {"Versions": [772, 771, 770, 769]}},
   132              {"Name": "CertCompressionAlgs", "Data": {"Algorithms": [2]}},
   133              {"Name": "ChannelID"},
   134              {"Name": "RecordSizeLimit", "Data": {"Limit": 9999}}],
   135            "GetSessionID": "SHA-256"
   136          }
   137        }
   138      ]`)
   139  
   140  	var customTLSProfiles CustomTLSProfiles
   141  
   142  	err := json.Unmarshal(customTLSProfilesJSON, &customTLSProfiles)
   143  	if err != nil {
   144  		t.Fatalf("Unmarshal failed: %s", err)
   145  	}
   146  
   147  	err = customTLSProfiles.Validate()
   148  	if err != nil {
   149  		t.Fatalf("Validate failed: %s", err)
   150  	}
   151  
   152  	profile := customTLSProfiles[0]
   153  	profileClientHelloSpec, err := profile.GetClientHelloSpec()
   154  	if err != nil {
   155  		t.Fatalf("GetClientHelloSpec failed: %s", err)
   156  	}
   157  
   158  	zeroes := make([]byte, 32)
   159  
   160  	conn1 := utls.UClient(nil, &utls.Config{InsecureSkipVerify: true}, utls.HelloCustom)
   161  	conn1.ApplyPreset(utlsClientHelloSpec)
   162  	conn1.SetClientRandom(zeroes)
   163  	conn1.HandshakeState.Hello.SessionId = zeroes
   164  	err = conn1.BuildHandshakeState()
   165  	if err != nil {
   166  		t.Fatalf("BuildHandshakeState failed: %s", err)
   167  	}
   168  
   169  	conn2 := utls.UClient(nil, &utls.Config{InsecureSkipVerify: true}, utls.HelloCustom)
   170  	conn2.ApplyPreset(profileClientHelloSpec)
   171  	conn2.SetClientRandom(zeroes)
   172  	conn2.HandshakeState.Hello.SessionId = zeroes
   173  	err = conn2.BuildHandshakeState()
   174  	if err != nil {
   175  		t.Fatalf("BuildHandshakeState failed: %s", err)
   176  	}
   177  
   178  	if len(conn1.HandshakeState.Hello.Raw) == 0 {
   179  		t.Fatalf("Missing raw ClientHello")
   180  	}
   181  
   182  	if len(conn2.HandshakeState.Hello.Raw) == 0 {
   183  		t.Fatalf("Missing raw ClientHello")
   184  	}
   185  
   186  	if !bytes.Equal(conn1.HandshakeState.Hello.Raw, conn2.HandshakeState.Hello.Raw) {
   187  		t.Fatalf("Unidentical raw ClientHellos")
   188  	}
   189  }