github.com/Psiphon-Labs/tls-tris@v0.0.0-20230824155421-58bf6d336a9a/obfuscated_test.go (about)

     1  /*
     2   * Copyright (c) 2016, 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 tls
    21  
    22  import (
    23  	"crypto/rand"
    24  	"crypto/rsa"
    25  	"crypto/sha1"
    26  	"crypto/x509"
    27  	"crypto/x509/pkix"
    28  	"encoding/pem"
    29  	"errors"
    30  	"io"
    31  	"math/big"
    32  	"net"
    33  	"testing"
    34  	"time"
    35  
    36  	utls "github.com/refraction-networking/utls"
    37  )
    38  
    39  // [Psiphon]
    40  // TestObfuscatedSessionTicket exercises the Obfuscated Session Tickets facility.
    41  func TestObfuscatedSessionTicket(t *testing.T) {
    42  
    43  	helloIDs := []utls.ClientHelloID{
    44  		utls.HelloChrome_Auto,
    45  		utls.HelloFirefox_Auto,
    46  	}
    47  
    48  	for _, helloID := range helloIDs {
    49  		t.Run(helloID.Str(), func(t *testing.T) {
    50  			runObfuscatedSessionTicket(t, helloID)
    51  		})
    52  	}
    53  }
    54  
    55  func runObfuscatedSessionTicket(t *testing.T, helloID utls.ClientHelloID) {
    56  
    57  	var standardSessionTicketKey [32]byte
    58  	rand.Read(standardSessionTicketKey[:])
    59  
    60  	var obfuscatedSessionTicketSharedSecret [32]byte
    61  	rand.Read(obfuscatedSessionTicketSharedSecret[:])
    62  
    63  	// Note: SNI and certificate CN intentionally don't match; if the
    64  	// session ticket is ignored, the TLS handshake will fail with
    65  	// a certificate error.
    66  	clientConfig := &utls.Config{
    67  		ServerName: "www.example.com",
    68  	}
    69  
    70  	certificate, err := generateCertificate()
    71  	if err != nil {
    72  		t.Fatalf("generateCertificate failed: %s", err)
    73  	}
    74  
    75  	serverConfig := &Config{
    76  		Certificates:     []Certificate{*certificate},
    77  		NextProtos:       []string{"http/1.1"},
    78  		MinVersion:       VersionTLS10,
    79  		SessionTicketKey: obfuscatedSessionTicketSharedSecret,
    80  	}
    81  
    82  	serverConfig.SetSessionTicketKeys([][32]byte{
    83  		standardSessionTicketKey, obfuscatedSessionTicketSharedSecret})
    84  
    85  	testMessage := "test"
    86  
    87  	result := make(chan error, 1)
    88  
    89  	report := func(err error) {
    90  		select {
    91  		case result <- err:
    92  		default:
    93  		}
    94  	}
    95  
    96  	listening := make(chan string, 1)
    97  
    98  	go func() {
    99  
   100  		listener, err := Listen("tcp", ":0", serverConfig)
   101  		if err != nil {
   102  			report(err)
   103  			return
   104  		}
   105  		defer listener.Close()
   106  
   107  		listening <- listener.Addr().String()
   108  
   109  		conn, err := listener.Accept()
   110  		if err != nil {
   111  			report(err)
   112  			return
   113  		}
   114  		defer conn.Close()
   115  
   116  		recv := make([]byte, len(testMessage))
   117  		_, err = io.ReadFull(conn, recv)
   118  		if err == nil && string(recv) != testMessage {
   119  			err = errors.New("unexpected payload")
   120  		}
   121  		if err != nil {
   122  			report(err)
   123  			return
   124  		}
   125  
   126  		// Sends nil on success
   127  		report(nil)
   128  	}()
   129  
   130  	go func() {
   131  
   132  		serverAddress := <-listening
   133  
   134  		tcpConn, err := net.Dial("tcp", serverAddress)
   135  		if err != nil {
   136  			report(err)
   137  			return
   138  		}
   139  		defer tcpConn.Close()
   140  
   141  		tlsConn := utls.UClient(tcpConn, clientConfig, helloID)
   142  
   143  		obfuscatedSessionState, err := NewObfuscatedClientSessionState(
   144  			obfuscatedSessionTicketSharedSecret)
   145  		if err != nil {
   146  			report(err)
   147  			return
   148  		}
   149  
   150  		sessionState := utls.MakeClientSessionState(
   151  			obfuscatedSessionState.SessionTicket,
   152  			obfuscatedSessionState.Vers,
   153  			obfuscatedSessionState.CipherSuite,
   154  			obfuscatedSessionState.MasterSecret,
   155  			nil,
   156  			nil)
   157  
   158  		tlsConn.SetSessionState(sessionState)
   159  
   160  		_, err = tlsConn.Write([]byte(testMessage))
   161  		if err != nil {
   162  			report(err)
   163  			return
   164  		}
   165  	}()
   166  
   167  	err = <-result
   168  	if err != nil {
   169  		t.Fatalf("connect failed: %s", err)
   170  	}
   171  }
   172  
   173  func generateCertificate() (*Certificate, error) {
   174  
   175  	rsaKey, err := rsa.GenerateKey(rand.Reader, 2048)
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  
   180  	publicKeyBytes, err := x509.MarshalPKIXPublicKey(rsaKey.Public())
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	subjectKeyID := sha1.Sum(publicKeyBytes)
   185  
   186  	template := x509.Certificate{
   187  		SerialNumber:          big.NewInt(1),
   188  		Subject:               pkix.Name{CommonName: "www.example.org"},
   189  		NotBefore:             time.Now().Add(-1 * time.Hour).UTC(),
   190  		NotAfter:              time.Now().Add(time.Hour).UTC(),
   191  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
   192  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
   193  		BasicConstraintsValid: true,
   194  		IsCA:                  true,
   195  		SubjectKeyId:          subjectKeyID[:],
   196  		MaxPathLen:            1,
   197  		Version:               2,
   198  	}
   199  
   200  	derCert, err := x509.CreateCertificate(
   201  		rand.Reader,
   202  		&template,
   203  		&template,
   204  		rsaKey.Public(),
   205  		rsaKey)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  
   210  	certificate := pem.EncodeToMemory(
   211  		&pem.Block{
   212  			Type:  "CERTIFICATE",
   213  			Bytes: derCert,
   214  		},
   215  	)
   216  
   217  	privateKey := pem.EncodeToMemory(
   218  		&pem.Block{
   219  			Type:  "RSA PRIVATE KEY",
   220  			Bytes: x509.MarshalPKCS1PrivateKey(rsaKey),
   221  		},
   222  	)
   223  
   224  	keyPair, err := X509KeyPair(certificate, privateKey)
   225  	if err != nil {
   226  		return nil, err
   227  	}
   228  
   229  	return &keyPair, nil
   230  }