tlsDialer_test.go 26 KB

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