Commit 37c2875 caused a regression in the tls package that causes some tests to fail.
This is my hypothesis (I'm not an expert in the TLS protocol):
Previously, in the event of a bad client certificate (using the ClientAuth feature), the server would inform the client that the client's certificate was rejected before returning from the Handshake method. After the change mentioned, it seems that Handshake would return before the client is informed of the failure.
Consider the following code (where the client is using a bad certificate and should fail the Handshake):
// Snippet of server-side logic.
if err := tc.(*tls.Conn).Handshake(); err != nil {
// If the client presented a bad cert, it seems reasonable to
// Close the connection immediately.
tc.Close()
}
// Snippet of client-side logic.
if err := c.Handshake(); err != nil {
// The client is intentionally using a bad certificate, so we expect that
// the error be "bad certificate". However, it is more often a "pipe error" instead.
panic(err)
}
If the server's Handshake returns before it informs the client of a bad certificate, then there is a race condition going on here. As the client's Handshake is asking the server for the status of the TLS handshake, the client's packet may be received by the server before the server calls tc.Close or it may be received after calling tc.Close. If received before, then the client's Handshake will properly return an "bad certificate" error. However, if received after, then the client's Handshake will return a "broken pipe" error, which is more indicative of a network failure, than an authentication error.
Putting a time.Sleep(time.Second) before calling tc.Close on the server makes the client's Handshake almost always return 'bad certificate', further indicating that this is a race.
See this example: https://play.golang.org/p/7aY0K9wcEW
@agl, @bradfitz
Commit 37c2875 caused a regression in the
tlspackage that causes some tests to fail.This is my hypothesis (I'm not an expert in the TLS protocol):
Previously, in the event of a bad client certificate (using the
ClientAuthfeature), the server would inform the client that the client's certificate was rejected before returning from the Handshake method. After the change mentioned, it seems that Handshake would return before the client is informed of the failure.Consider the following code (where the client is using a bad certificate and should fail the Handshake):
If the server's
Handshakereturns before it informs the client of a bad certificate, then there is a race condition going on here. As the client'sHandshakeis asking the server for the status of the TLS handshake, the client's packet may be received by the server before the server callstc.Closeor it may be received after callingtc.Close. If received before, then the client'sHandshakewill properly return an "bad certificate" error. However, if received after, then the client'sHandshakewill return a "broken pipe" error, which is more indicative of a network failure, than an authentication error.Putting a
time.Sleep(time.Second)before callingtc.Closeon the server makes the client'sHandshakealmost always return 'bad certificate', further indicating that this is a race.See this example: https://play.golang.org/p/7aY0K9wcEW
@agl, @bradfitz