Skip to content

Commit be0f3c2

Browse files
committed
crypto/tls: replace net.Pipe in tests with real TCP connections
crypto/tls is meant to work over network connections with buffering, not synchronous connections, as explained in #24198. Tests based on net.Pipe are unrealistic as reads and writes are matched one to one. Such tests worked just thanks to the implementation details of the tls.Conn internal buffering, and would break if for example the flush of the first flight of the server was not entirely assimilated by the client rawInput buffer before the client attempted to reply to the ServerHello. Note that this might run into the Darwin network issues at #25696. Fixed a few test races that were either hidden or synchronized by the use of the in-memory net.Pipe. Also, this gets us slightly more realistic benchmarks, reflecting some syscall cost of Read and Write operations. Change-Id: I5a597b3d7a81b8ccc776030cc837133412bf50f8 Reviewed-on: https://go-review.googlesource.com/c/142817 Run-TryBot: Filippo Valsorda <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 628403f commit be0f3c2

File tree

4 files changed

+107
-58
lines changed

4 files changed

+107
-58
lines changed

src/crypto/tls/conn_test.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,13 @@ func TestCertificateSelection(t *testing.T) {
134134

135135
// Run with multiple crypto configs to test the logic for computing TLS record overheads.
136136
func runDynamicRecordSizingTest(t *testing.T, config *Config) {
137-
clientConn, serverConn := net.Pipe()
137+
clientConn, serverConn := localPipe(t)
138138

139139
serverConfig := config.Clone()
140140
serverConfig.DynamicRecordSizingDisabled = false
141141
tlsConn := Server(serverConn, serverConfig)
142142

143+
handshakeDone := make(chan struct{})
143144
recordSizesChan := make(chan []int, 1)
144145
go func() {
145146
// This goroutine performs a TLS handshake over clientConn and
@@ -153,6 +154,7 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) {
153154
t.Errorf("Error from client handshake: %v", err)
154155
return
155156
}
157+
close(handshakeDone)
156158

157159
var recordHeader [recordHeaderLen]byte
158160
var record []byte
@@ -192,6 +194,7 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) {
192194
if err := tlsConn.Handshake(); err != nil {
193195
t.Fatalf("Error from server handshake: %s", err)
194196
}
197+
<-handshakeDone
195198

196199
// The server writes these plaintexts in order.
197200
plaintext := bytes.Join([][]byte{
@@ -269,7 +272,7 @@ func (conn *hairpinConn) Close() error {
269272
func TestHairpinInClose(t *testing.T) {
270273
// This tests that the underlying net.Conn can call back into the
271274
// tls.Conn when being closed without deadlocking.
272-
client, server := net.Pipe()
275+
client, server := localPipe(t)
273276
defer server.Close()
274277
defer client.Close()
275278

src/crypto/tls/handshake_client_test.go

+18-18
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
179179
var pemOut bytes.Buffer
180180
pem.Encode(&pemOut, &pem.Block{Type: pemType + " PRIVATE KEY", Bytes: derBytes})
181181

182-
keyPath := tempFile(string(pemOut.Bytes()))
182+
keyPath := tempFile(pemOut.String())
183183
defer os.Remove(keyPath)
184184

185185
var command []string
@@ -293,7 +293,7 @@ func (test *clientTest) run(t *testing.T, write bool) {
293293
}
294294
clientConn = recordingConn
295295
} else {
296-
clientConn, serverConn = net.Pipe()
296+
clientConn, serverConn = localPipe(t)
297297
}
298298

299299
config := test.config
@@ -682,7 +682,7 @@ func TestClientResumption(t *testing.T) {
682682
}
683683

684684
testResumeState := func(test string, didResume bool) {
685-
_, hs, err := testHandshake(clientConfig, serverConfig)
685+
_, hs, err := testHandshake(t, clientConfig, serverConfig)
686686
if err != nil {
687687
t.Fatalf("%s: handshake failed: %s", test, err)
688688
}
@@ -800,7 +800,7 @@ func TestKeyLog(t *testing.T) {
800800
serverConfig := testConfig.Clone()
801801
serverConfig.KeyLogWriter = &serverBuf
802802

803-
c, s := net.Pipe()
803+
c, s := localPipe(t)
804804
done := make(chan bool)
805805

806806
go func() {
@@ -838,8 +838,8 @@ func TestKeyLog(t *testing.T) {
838838
}
839839
}
840840

841-
checkKeylogLine("client", string(clientBuf.Bytes()))
842-
checkKeylogLine("server", string(serverBuf.Bytes()))
841+
checkKeylogLine("client", clientBuf.String())
842+
checkKeylogLine("server", serverBuf.String())
843843
}
844844

845845
func TestHandshakeClientALPNMatch(t *testing.T) {
@@ -1021,7 +1021,7 @@ var hostnameInSNITests = []struct {
10211021

10221022
func TestHostnameInSNI(t *testing.T) {
10231023
for _, tt := range hostnameInSNITests {
1024-
c, s := net.Pipe()
1024+
c, s := localPipe(t)
10251025

10261026
go func(host string) {
10271027
Client(c, &Config{ServerName: host, InsecureSkipVerify: true}).Handshake()
@@ -1059,7 +1059,7 @@ func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
10591059
// This checks that the server can't select a cipher suite that the
10601060
// client didn't offer. See #13174.
10611061

1062-
c, s := net.Pipe()
1062+
c, s := localPipe(t)
10631063
errChan := make(chan error, 1)
10641064

10651065
go func() {
@@ -1228,7 +1228,7 @@ func TestVerifyPeerCertificate(t *testing.T) {
12281228
}
12291229

12301230
for i, test := range tests {
1231-
c, s := net.Pipe()
1231+
c, s := localPipe(t)
12321232
done := make(chan error)
12331233

12341234
var clientCalled, serverCalled bool
@@ -1287,7 +1287,7 @@ func (b *brokenConn) Write(data []byte) (int, error) {
12871287
func TestFailedWrite(t *testing.T) {
12881288
// Test that a write error during the handshake is returned.
12891289
for _, breakAfter := range []int{0, 1} {
1290-
c, s := net.Pipe()
1290+
c, s := localPipe(t)
12911291
done := make(chan bool)
12921292

12931293
go func() {
@@ -1321,7 +1321,7 @@ func (wcc *writeCountingConn) Write(data []byte) (int, error) {
13211321
}
13221322

13231323
func TestBuffering(t *testing.T) {
1324-
c, s := net.Pipe()
1324+
c, s := localPipe(t)
13251325
done := make(chan bool)
13261326

13271327
clientWCC := &writeCountingConn{Conn: c}
@@ -1350,7 +1350,7 @@ func TestBuffering(t *testing.T) {
13501350
}
13511351

13521352
func TestAlertFlushing(t *testing.T) {
1353-
c, s := net.Pipe()
1353+
c, s := localPipe(t)
13541354
done := make(chan bool)
13551355

13561356
clientWCC := &writeCountingConn{Conn: c}
@@ -1399,7 +1399,7 @@ func TestHandshakeRace(t *testing.T) {
13991399
// order to provide some evidence that there are no races or deadlocks
14001400
// in the handshake locking.
14011401
for i := 0; i < 32; i++ {
1402-
c, s := net.Pipe()
1402+
c, s := localPipe(t)
14031403

14041404
go func() {
14051405
server := Server(s, testConfig)
@@ -1430,7 +1430,7 @@ func TestHandshakeRace(t *testing.T) {
14301430
go func() {
14311431
<-startRead
14321432
var reply [1]byte
1433-
if n, err := client.Read(reply[:]); err != nil || n != 1 {
1433+
if _, err := io.ReadFull(client, reply[:]); err != nil {
14341434
panic(err)
14351435
}
14361436
c.Close()
@@ -1559,7 +1559,7 @@ func TestGetClientCertificate(t *testing.T) {
15591559
err error
15601560
}
15611561

1562-
c, s := net.Pipe()
1562+
c, s := localPipe(t)
15631563
done := make(chan serverResult)
15641564

15651565
go func() {
@@ -1637,7 +1637,7 @@ RwBA9Xk1KBNF
16371637
}
16381638

16391639
func TestCloseClientConnectionOnIdleServer(t *testing.T) {
1640-
clientConn, serverConn := net.Pipe()
1640+
clientConn, serverConn := localPipe(t)
16411641
client := Client(clientConn, testConfig.Clone())
16421642
go func() {
16431643
var b [1]byte
@@ -1647,8 +1647,8 @@ func TestCloseClientConnectionOnIdleServer(t *testing.T) {
16471647
client.SetWriteDeadline(time.Now().Add(time.Second))
16481648
err := client.Handshake()
16491649
if err != nil {
1650-
if !strings.Contains(err.Error(), "read/write on closed pipe") {
1651-
t.Errorf("Error expected containing 'read/write on closed pipe' but got '%s'", err.Error())
1650+
if err, ok := err.(net.Error); ok && err.Timeout() {
1651+
t.Errorf("Expected a closed network connection error but got '%s'", err.Error())
16521652
}
16531653
} else {
16541654
t.Errorf("Error expected, but no error returned")

0 commit comments

Comments
 (0)