utls/u_conn_test.go
2025-02-10 12:30:47 -07:00

745 lines
22 KiB
Go

// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tls
import (
"bytes"
"crypto/tls"
"fmt"
"io"
"net"
"os"
"os/exec"
"runtime/debug"
"strings"
"testing"
"time"
)
// helloStrategy is a sum type interface which allows us to pass either a ClientHelloID or a ClientHelloSpec and then act accordingly
type helloStrategy interface {
helloName() string
}
type helloID struct {
id ClientHelloID
}
func (hid *helloID) helloName() string {
return hid.id.Str()
}
type helloSpec struct {
name string
spec *ClientHelloSpec
}
func (hs *helloSpec) helloName() string {
return hs.name
}
func TestUTLSMarshalNoOp(t *testing.T) {
str := "We rely on clientHelloMsg.marshal() not doing anything if clientHelloMsg.raw is set"
uconn := UClient(&net.TCPConn{}, &Config{ServerName: "foobar"}, HelloGolang)
msg, _, _, err := uconn.makeClientHello()
if err != nil {
t.Errorf("Got error: %s; expected to succeed", err)
}
msg.original = []byte(str)
marshalledHello, err := msg.marshal()
if err != nil {
t.Errorf("clientHelloMsg.marshal() returned error: %s", err.Error())
}
if strings.Compare(string(marshalledHello), str) != 0 {
t.Errorf("clientHelloMsg.marshal() is not NOOP! Expected to get: %s, got: %s", str, string(marshalledHello))
}
}
func TestUTLSHandshakeClientParrotGolang(t *testing.T) {
hello := &helloID{HelloGolang}
t.Skip("Skipping golang parroting tests until adjusting for new fingerprints")
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, hello)
}
func TestUTLSHandshakeClientParrotChrome_70(t *testing.T) {
hello := &helloID{HelloChrome_70}
testUTLSHandshakeClientTLS13_AES_128_GCM_SHA256(t, hello)
testUTLSHandshakeClientTLS13_AES_256_GCM_SHA384(t, hello)
testUTLSHandshakeClientTLS13_CHACHA20_POLY1305_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, hello)
}
func TestUTLSHandshakeClientParrotChrome_58(t *testing.T) {
hello := &helloID{HelloChrome_58}
// TODO: EC tests below are disabled because latest version of reference OpenSSL doesn't support p256 nor p384
// nor X25519 and I can't find configuration flag to enable it. Therefore I can't record replays.
//testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t, hello)
}
func TestUTLSHandshakeClientParrotFirefox_63(t *testing.T) {
hello := &helloID{HelloFirefox_63}
testUTLSHandshakeClientTLS13_AES_128_GCM_SHA256(t, hello)
testUTLSHandshakeClientTLS13_AES_256_GCM_SHA384(t, hello)
testUTLSHandshakeClientTLS13_CHACHA20_POLY1305_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, hello) TODO: enable when OpenSSL supports it
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
}
func TestUTLSHandshakeClientParrotFirefox_55(t *testing.T) {
hello := &helloID{HelloFirefox_55}
testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t, hello)
testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t, hello)
//testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t, hello) TODO: enable when OpenSSL supports it
testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t, hello)
testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t, hello)
}
func TestUTLSHandshakeClientParrotChrome_58_setclienthello(t *testing.T) {
hello := &helloID{HelloChrome_58}
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-setclienthello-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
// tests consistency of fingerprint after HelloRetryRequest
// chrome 70 is used, due to only specifying X25519 in keyshare, but being able to generate P-256 curve too
// openssl server, configured to use P-256, will send HelloRetryRequest
func TestUTLSHelloRetryRequest(t *testing.T) {
hello := &helloID{HelloChrome_70}
config := testConfig.Clone()
config.CurvePreferences = []CurveID{X25519, CurveP256}
test := &clientTest{
name: "UTLS-HelloRetryRequest-" + hello.helloName(),
args: []string{"-cipher", "ECDHE-RSA-AES128-GCM-SHA256", "-curves", "P-256"},
config: config,
}
runUTLSClientTestTLS13(t, test, hello)
}
func TestUTLSRemoveSNIExtension(t *testing.T) {
hello := &helloID{HelloChrome_70}
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName() + "-OmitSNI",
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestForVersion(t, test, "TLSv12-", "-tls1_2", hello, true)
}
func TestUTLSServerNameIP(t *testing.T) {
hello := &helloID{HelloChrome_70}
config := getUTLSTestConfig()
config.ServerName = "1.1.1.1"
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName() + "-ServerNameIP",
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestForVersion(t, test, "TLSv12-", "-tls1_2", hello, true)
}
func TestUTLSEmptyServerName(t *testing.T) {
hello := &helloID{HelloChrome_70}
config := getUTLSTestConfig()
config.ServerName = ""
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName() + "-EmptyServerName",
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestForVersion(t, test, "TLSv12-", "-tls1_2", hello, true)
}
/*
*
HELPER FUNCTIONS BELOW
*
*/
func getUTLSTestConfig() *Config {
testUTLSConfig := &Config{
Time: func() time.Time {
return time.Unix(0, 0)
},
Rand: zeroSource{},
InsecureSkipVerify: true,
MinVersion: VersionSSL30,
MaxVersion: VersionTLS13,
CipherSuites: allCipherSuites(),
ServerName: "foobar.com",
}
return testUTLSConfig
}
func testUTLSHandshakeClientECDHE_RSA_AES128_CBC_SHA(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-SHA"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_RSA_AES256_CBC_SHA(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES256-SHA"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_AES128_CBC_SHA(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-ECDSA-AES128-SHA"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_AES256_CBC_SHA(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-ECDSA-AES256-SHA"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientRSA_AES128_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_AES128_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-ECDSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_RSA_AES128_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_AES256_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-ECDSA-AES256-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
cert: testECDSACertificate,
key: testECDSAPrivateKey,
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_RSA_AES256_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "ECDHE-RSA-AES128-GCM-SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientTLS13_AES_128_GCM_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "TLS_AES_128_GCM_SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
}
runUTLSClientTestTLS13(t, test, hello)
}
func testUTLSHandshakeClientTLS13_AES_256_GCM_SHA384(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "TLS_AES_256_GCM_SHA384"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
}
runUTLSClientTestTLS13(t, test, hello)
}
func testUTLSHandshakeClientTLS13_CHACHA20_POLY1305_SHA256(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
opensslCipherName := "TLS_CHACHA20_POLY1305_SHA256"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-ciphersuites", opensslCipherName},
config: config,
}
runUTLSClientTestTLS13(t, test, hello)
}
func testUTLSHandshakeClientECDHE_RSA_WITH_CHACHA20_POLY1305(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305}
opensslCipherName := "ECDHE-RSA-CHACHA20-POLY1305"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
}
runUTLSClientTestTLS12(t, test, hello)
}
func testUTLSHandshakeClientECDHE_ECDSA_WITH_CHACHA20_POLY1305(t *testing.T, hello helloStrategy) {
config := getUTLSTestConfig()
config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305}
opensslCipherName := "ECDHE-ECDSA-CHACHA20-POLY1305"
test := &clientTest{
name: "UTLS-" + opensslCipherName + "-" + hello.helloName(),
args: []string{"-cipher", opensslCipherName},
config: config,
cert: testECDSACertificate,
key: testECDSAPrivateKey,
}
runUTLSClientTestTLS12(t, test, hello)
}
func runUTLSClientTestForVersion(t *testing.T, template *clientTest, prefix, option string, hello helloStrategy, omitSNI bool) {
test := *template
test.name = prefix + test.name
if len(test.args) == 0 {
test.args = defaultClientCommand
}
test.args = append([]string(nil), test.args...)
test.args = append(test.args, option)
test.runUTLS(t, *update, hello, omitSNI)
}
func runUTLSClientTestTLS12(t *testing.T, template *clientTest, hello helloStrategy) {
runUTLSClientTestForVersion(t, template, "TLSv12-", "-tls1_2", hello, false)
}
func runUTLSClientTestTLS13(t *testing.T, template *clientTest, hello helloStrategy) {
runUTLSClientTestForVersion(t, template, "TLSv13-", "-tls1_3", hello, false)
}
func (test *clientTest) runUTLS(t *testing.T, write bool, hello helloStrategy, omitSNIExtension bool) {
checkOpenSSLVersion()
var clientConn, serverConn net.Conn
var recordingConn *recordingConn
var childProcess *exec.Cmd
var stdin opensslInput
var stdout *opensslOutputSink
if write {
var err error
recordingConn, childProcess, stdin, stdout, err = test.connFromCommand()
if err != nil {
t.Fatalf("Failed to start subcommand: %s", err)
}
clientConn = recordingConn
} else {
clientConn, serverConn = localPipe(t)
}
config := test.config
if config == nil {
t.Error("Explicit config is mandatory")
return
}
var client *UConn
switch h := hello.(type) {
case *helloID:
client = UClient(clientConn, config, h.id)
case *helloSpec:
client = UClient(clientConn, config, HelloCustom)
if err := client.ApplyPreset(h.spec); err != nil {
t.Errorf("got error: %v; expected to succeed", err)
return
}
default:
panic("unknown helloStrategy")
}
if omitSNIExtension {
if err := client.RemoveSNIExtension(); err != nil {
t.Error("Failed to remove SNI extension")
return
}
}
if strings.HasPrefix(test.name, "TLSv12-UTLS-setclienthello-") {
err := client.BuildHandshakeState()
if err != nil {
t.Errorf("Client.BuildHandshakeState() failed: %s", err)
return
}
// TODO: fix this name hack if we ever decide to use non-standard testing object
err = client.SetClientRandom([]byte("Custom ClientRandom h^xbw8bf0sn3"))
if err != nil {
t.Errorf("Client.SetClientRandom() failed: %s", err)
return
}
}
doneChan := make(chan bool)
go func() {
defer func() {
if err := recover(); err != nil {
fmt.Printf("panic occurred: %v\n %s\n", err, string(debug.Stack()))
}
// Give time to the send buffer to drain, to avoid the kernel
// sending a RST and cutting off the flow. See Issue 18701.
time.Sleep(10 * time.Millisecond)
client.Close()
clientConn.Close()
doneChan <- true
}()
if _, err := client.Write([]byte("hello\n")); err != nil {
t.Errorf("Client.Write failed: %s", err)
return
}
for i := 1; i <= test.numRenegotiations; i++ {
// The initial handshake will generate a
// handshakeComplete signal which needs to be quashed.
if i == 1 && write {
<-stdout.handshakeComplete
}
// OpenSSL will try to interleave application data and
// a renegotiation if we send both concurrently.
// Therefore: ask OpensSSL to start a renegotiation, run
// a goroutine to call client.Read and thus process the
// renegotiation request, watch for OpenSSL's stdout to
// indicate that the handshake is complete and,
// finally, have OpenSSL write something to cause
// client.Read to complete.
if write {
stdin <- opensslRenegotiate
}
signalChan := make(chan struct{})
go func() {
defer close(signalChan)
buf := make([]byte, 256)
n, err := client.Read(buf)
if test.checkRenegotiationError != nil {
newErr := test.checkRenegotiationError(i, err)
if err != nil && newErr == nil {
return
}
err = newErr
}
if err != nil {
t.Errorf("Client.Read failed after renegotiation #%d: %s", i, err)
return
}
buf = buf[:n]
if !bytes.Equal([]byte(opensslSentinel), buf) {
t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
}
if expected := i + 1; client.handshakes != expected {
t.Errorf("client should have recorded %d handshakes, but believes that %d have occurred", expected, client.handshakes)
}
}()
if write && test.renegotiationExpectedToFail != i {
<-stdout.handshakeComplete
stdin <- opensslSendSentinel
}
<-signalChan
}
if test.sendKeyUpdate {
if write {
<-stdout.handshakeComplete
stdin <- opensslKeyUpdate
}
doneRead := make(chan struct{})
go func() {
defer close(doneRead)
buf := make([]byte, 256)
n, err := client.Read(buf)
if err != nil {
t.Errorf("Client.Read failed after KeyUpdate: %s", err)
return
}
buf = buf[:n]
if !bytes.Equal([]byte(opensslSentinel), buf) {
t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
}
}()
if write {
// There's no real reason to wait for the client KeyUpdate to
// send data with the new server keys, except that s_server
// drops writes if they are sent at the wrong time.
<-stdout.readKeyUpdate
stdin <- opensslSendSentinel
}
<-doneRead
if _, err := client.Write([]byte("hello again\n")); err != nil {
t.Errorf("Client.Write failed: %s", err)
return
}
}
if test.validate != nil {
if err := test.validate(client.ConnectionState()); err != nil {
t.Errorf("validate callback returned error: %s", err)
}
}
// If the server sent us an alert after our last flight, give it a
// chance to arrive.
if write && test.renegotiationExpectedToFail == 0 {
client.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
if _, err := client.Read(make([]byte, 1)); err != nil {
if netErr, ok := err.(net.Error); !ok || !netErr.Timeout() {
t.Errorf("final Read returned an error: %s", err)
}
}
}
}()
if !write {
flows, err := test.loadData()
if err != nil {
t.Fatalf("%s: failed to load data from %s: %v", test.name, test.dataPath(), err)
}
for i, b := range flows {
if i%2 == 1 {
serverConn.SetWriteDeadline(time.Now().Add(2 * time.Second)) // [uTLS] 1min -> 2sec
serverConn.Write(b)
continue
}
bb := make([]byte, len(b))
serverConn.SetReadDeadline(time.Now().Add(2 * time.Second)) // [uTLS] 1min -> 2sec
_, err := io.ReadFull(serverConn, bb)
if err != nil {
t.Fatalf("%s #%d: %s", test.name, i, err)
}
if !bytes.Equal(b, bb) {
t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i, bb, b)
}
}
// Give time to the send buffer to drain, to avoid the kernel
// sending a RST and cutting off the flow. See Issue 18701.
time.Sleep(10 * time.Millisecond)
serverConn.Close()
}
<-doneChan
if write {
path := test.dataPath()
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
t.Fatalf("Failed to create output file: %s", err)
}
defer out.Close()
recordingConn.Close()
close(stdin)
childProcess.Process.Kill()
childProcess.Wait()
if len(recordingConn.flows) < 3 {
os.Stdout.Write(stdout.all)
t.Fatalf("Client connection didn't work")
}
recordingConn.WriteTo(out)
fmt.Printf("Wrote %s\n", path)
}
}
func TestUTLSMakeConnWithCompleteHandshake(t *testing.T) {
serverConn, clientConn := net.Pipe()
masterSecret := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}
clientRandom := []byte{40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71}
serverRandom := []byte{80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}
serverTls := MakeConnWithCompleteHandshake(serverConn, tls.VersionTLS12, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
masterSecret, clientRandom, serverRandom, false)
clientTls := MakeConnWithCompleteHandshake(clientConn, tls.VersionTLS12, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
masterSecret, clientRandom, serverRandom, true)
clientMsg := []byte("Hello, world!")
serverMsg := []byte("Test response!")
go func() {
clientTls.Write(clientMsg)
resp := make([]byte, 20)
read, err := clientTls.Read(resp)
if !bytes.Equal(resp[:read], serverMsg) {
t.Errorf("client expected to receive: %v, got %v\n",
serverMsg, resp[:read])
}
if err != nil {
t.Errorf("error reading client: %+v\n", err)
}
clientConn.Close()
}()
buf := make([]byte, 20)
read, err := serverTls.Read(buf)
if !bytes.Equal(buf[:read], clientMsg) {
t.Errorf("server expected to receive: %v, got %v\n",
clientMsg, buf[:read])
}
if err != nil {
t.Errorf("error reading client: %+v\n", err)
}
serverTls.Write(serverMsg)
}