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 }