mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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 <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
628403fd6b
commit
be0f3c286b
4 changed files with 107 additions and 58 deletions
|
|
@ -70,10 +70,7 @@ func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
|
|||
}
|
||||
|
||||
func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) {
|
||||
// Create in-memory network connection,
|
||||
// send message to server. Should return
|
||||
// expected error.
|
||||
c, s := net.Pipe()
|
||||
c, s := localPipe(t)
|
||||
go func() {
|
||||
cli := Client(c, testConfig)
|
||||
if ch, ok := m.(*clientHelloMsg); ok {
|
||||
|
|
@ -201,25 +198,26 @@ func TestRenegotiationExtension(t *testing.T) {
|
|||
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
c, s := net.Pipe()
|
||||
bufChan := make(chan []byte)
|
||||
c, s := localPipe(t)
|
||||
|
||||
go func() {
|
||||
cli := Client(c, testConfig)
|
||||
cli.vers = clientHello.vers
|
||||
cli.writeRecord(recordTypeHandshake, clientHello.marshal())
|
||||
|
||||
buf = make([]byte, 1024)
|
||||
buf := make([]byte, 1024)
|
||||
n, err := c.Read(buf)
|
||||
if err != nil {
|
||||
t.Errorf("Server read returned error: %s", err)
|
||||
return
|
||||
}
|
||||
buf = buf[:n]
|
||||
c.Close()
|
||||
bufChan <- buf[:n]
|
||||
}()
|
||||
|
||||
Server(s, testConfig).Handshake()
|
||||
buf := <-bufChan
|
||||
|
||||
if len(buf) < 5+4 {
|
||||
t.Fatalf("Server returned short message of length %d", len(buf))
|
||||
|
|
@ -262,22 +260,27 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
|
|||
supportedPoints: []uint8{pointFormatUncompressed},
|
||||
}
|
||||
|
||||
c, s := net.Pipe()
|
||||
var reply interface{}
|
||||
var clientErr error
|
||||
c, s := localPipe(t)
|
||||
replyChan := make(chan interface{})
|
||||
go func() {
|
||||
cli := Client(c, testConfig)
|
||||
cli.vers = clientHello.vers
|
||||
cli.writeRecord(recordTypeHandshake, clientHello.marshal())
|
||||
reply, clientErr = cli.readHandshake()
|
||||
reply, err := cli.readHandshake()
|
||||
c.Close()
|
||||
if err != nil {
|
||||
replyChan <- err
|
||||
} else {
|
||||
replyChan <- reply
|
||||
}
|
||||
}()
|
||||
config := testConfig.Clone()
|
||||
config.CipherSuites = clientHello.cipherSuites
|
||||
Server(s, config).Handshake()
|
||||
s.Close()
|
||||
if clientErr != nil {
|
||||
t.Fatal(clientErr)
|
||||
reply := <-replyChan
|
||||
if err, ok := reply.(error); ok {
|
||||
t.Fatal(err)
|
||||
}
|
||||
serverHello, ok := reply.(*serverHelloMsg)
|
||||
if !ok {
|
||||
|
|
@ -289,7 +292,7 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAlertForwarding(t *testing.T) {
|
||||
c, s := net.Pipe()
|
||||
c, s := localPipe(t)
|
||||
go func() {
|
||||
Client(c, testConfig).sendAlert(alertUnknownCA)
|
||||
c.Close()
|
||||
|
|
@ -303,7 +306,7 @@ func TestAlertForwarding(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
c, s := net.Pipe()
|
||||
c, s := localPipe(t)
|
||||
go c.Close()
|
||||
|
||||
err := Server(s, testConfig).Handshake()
|
||||
|
|
@ -313,8 +316,8 @@ func TestClose(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func testHandshake(clientConfig, serverConfig *Config) (serverState, clientState ConnectionState, err error) {
|
||||
c, s := net.Pipe()
|
||||
func testHandshake(t *testing.T, clientConfig, serverConfig *Config) (serverState, clientState ConnectionState, err error) {
|
||||
c, s := localPipe(t)
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
cli := Client(c, clientConfig)
|
||||
|
|
@ -341,7 +344,7 @@ func TestVersion(t *testing.T) {
|
|||
clientConfig := &Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
state, _, err := testHandshake(clientConfig, serverConfig)
|
||||
state, _, err := testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
|
|
@ -360,7 +363,7 @@ func TestCipherSuitePreference(t *testing.T) {
|
|||
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA},
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
state, _, err := testHandshake(clientConfig, serverConfig)
|
||||
state, _, err := testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
|
|
@ -370,7 +373,7 @@ func TestCipherSuitePreference(t *testing.T) {
|
|||
}
|
||||
|
||||
serverConfig.PreferServerCipherSuites = true
|
||||
state, _, err = testHandshake(clientConfig, serverConfig)
|
||||
state, _, err = testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
|
|
@ -391,7 +394,7 @@ func TestSCTHandshake(t *testing.T) {
|
|||
clientConfig := &Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
_, state, err := testHandshake(clientConfig, serverConfig)
|
||||
_, state, err := testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
|
|
@ -420,13 +423,13 @@ func TestCrossVersionResume(t *testing.T) {
|
|||
|
||||
// Establish a session at TLS 1.1.
|
||||
clientConfig.MaxVersion = VersionTLS11
|
||||
_, _, err := testHandshake(clientConfig, serverConfig)
|
||||
_, _, err := testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
|
||||
// The client session cache now contains a TLS 1.1 session.
|
||||
state, _, err := testHandshake(clientConfig, serverConfig)
|
||||
state, _, err := testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
|
|
@ -436,7 +439,7 @@ func TestCrossVersionResume(t *testing.T) {
|
|||
|
||||
// Test that the server will decline to resume at a lower version.
|
||||
clientConfig.MaxVersion = VersionTLS10
|
||||
state, _, err = testHandshake(clientConfig, serverConfig)
|
||||
state, _, err = testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
|
|
@ -445,7 +448,7 @@ func TestCrossVersionResume(t *testing.T) {
|
|||
}
|
||||
|
||||
// The client session cache now contains a TLS 1.0 session.
|
||||
state, _, err = testHandshake(clientConfig, serverConfig)
|
||||
state, _, err = testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
|
|
@ -455,7 +458,7 @@ func TestCrossVersionResume(t *testing.T) {
|
|||
|
||||
// Test that the server will decline to resume at a higher version.
|
||||
clientConfig.MaxVersion = VersionTLS11
|
||||
state, _, err = testHandshake(clientConfig, serverConfig)
|
||||
state, _, err = testHandshake(t, clientConfig, serverConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("handshake failed: %s", err)
|
||||
}
|
||||
|
|
@ -579,7 +582,7 @@ func (test *serverTest) run(t *testing.T, write bool) {
|
|||
}
|
||||
serverConn = recordingConn
|
||||
} else {
|
||||
clientConn, serverConn = net.Pipe()
|
||||
clientConn, serverConn = localPipe(t)
|
||||
}
|
||||
config := test.config
|
||||
if config == nil {
|
||||
|
|
@ -832,7 +835,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
|
|||
nameToCert := config.NameToCertificate
|
||||
config.NameToCertificate = nil
|
||||
config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
|
||||
cert, _ := nameToCert[clientHello.ServerName]
|
||||
cert := nameToCert[clientHello.ServerName]
|
||||
return cert, nil
|
||||
}
|
||||
test := &serverTest{
|
||||
|
|
@ -1025,7 +1028,7 @@ func benchmarkHandshakeServer(b *testing.B, cipherSuite uint16, curve CurveID, c
|
|||
config.Certificates[0].PrivateKey = key
|
||||
config.BuildNameToCertificate()
|
||||
|
||||
clientConn, serverConn := net.Pipe()
|
||||
clientConn, serverConn := localPipe(b)
|
||||
serverConn = &recordingConn{Conn: serverConn}
|
||||
go func() {
|
||||
client := Client(clientConn, testConfig)
|
||||
|
|
@ -1039,7 +1042,7 @@ func benchmarkHandshakeServer(b *testing.B, cipherSuite uint16, curve CurveID, c
|
|||
flows := serverConn.(*recordingConn).flows
|
||||
|
||||
feeder := make(chan struct{})
|
||||
clientConn, serverConn = net.Pipe()
|
||||
clientConn, serverConn = localPipe(b)
|
||||
|
||||
go func() {
|
||||
for range feeder {
|
||||
|
|
@ -1051,10 +1054,10 @@ func benchmarkHandshakeServer(b *testing.B, cipherSuite uint16, curve CurveID, c
|
|||
ff := make([]byte, len(f))
|
||||
n, err := io.ReadFull(clientConn, ff)
|
||||
if err != nil {
|
||||
b.Fatalf("#%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", i+1, err, n, len(ff), ff[:n], f)
|
||||
b.Errorf("#%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", i+1, err, n, len(ff), ff[:n], f)
|
||||
}
|
||||
if !bytes.Equal(f, ff) {
|
||||
b.Fatalf("#%d: mismatch on read: got:%x want:%x", i+1, ff, f)
|
||||
b.Errorf("#%d: mismatch on read: got:%x want:%x", i+1, ff, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1216,7 +1219,7 @@ func TestSNIGivenOnFailure(t *testing.T) {
|
|||
// Erase the server's cipher suites to ensure the handshake fails.
|
||||
serverConfig.CipherSuites = nil
|
||||
|
||||
c, s := net.Pipe()
|
||||
c, s := localPipe(t)
|
||||
go func() {
|
||||
cli := Client(c, testConfig)
|
||||
cli.vers = clientHello.vers
|
||||
|
|
@ -1346,7 +1349,7 @@ func TestGetConfigForClient(t *testing.T) {
|
|||
configReturned = config
|
||||
return config, err
|
||||
}
|
||||
c, s := net.Pipe()
|
||||
c, s := localPipe(t)
|
||||
done := make(chan error)
|
||||
|
||||
go func() {
|
||||
|
|
@ -1423,7 +1426,7 @@ var testECDSAPrivateKey = &ecdsa.PrivateKey{
|
|||
var testP256PrivateKey, _ = x509.ParseECPrivateKey(fromHex("30770201010420012f3b52bc54c36ba3577ad45034e2e8efe1e6999851284cb848725cfe029991a00a06082a8648ce3d030107a14403420004c02c61c9b16283bbcc14956d886d79b358aa614596975f78cece787146abf74c2d5dc578c0992b4f3c631373479ebf3892efe53d21c4f4f1cc9a11c3536b7f75"))
|
||||
|
||||
func TestCloseServerConnectionOnIdleClient(t *testing.T) {
|
||||
clientConn, serverConn := net.Pipe()
|
||||
clientConn, serverConn := localPipe(t)
|
||||
server := Server(serverConn, testConfig.Clone())
|
||||
go func() {
|
||||
clientConn.Write([]byte{'0'})
|
||||
|
|
@ -1432,8 +1435,8 @@ func TestCloseServerConnectionOnIdleClient(t *testing.T) {
|
|||
server.SetReadDeadline(time.Now().Add(time.Second))
|
||||
err := server.Handshake()
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "read/write on closed pipe") {
|
||||
t.Errorf("Error expected containing 'read/write on closed pipe' but got '%s'", err.Error())
|
||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||
t.Errorf("Expected a closed network connection error but got '%s'", err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Errorf("Error expected, but no error returned")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue