TLS handshake through net.Pipe()

513 views
Skip to first unread message

Madhusudan C.S

unread,
Aug 17, 2016, 12:01:00 PM8/17/16
to golan...@googlegroups.com
I am writing some test code where I am creating `tls.Server()` and `tls.Client()` using the `Conn` pair returned by `net.Pipe()`. I have a few positive tests (where the Handshakes are expected to succeed) and a few negative tests (where the Handshakes are expected to fail). Each test sets up a `tls.Config` pair for a client and a server and runs `server.Handshake()` and `client.Handshake()` in separate goroutines. The positive tests run fine, but the negative tests hang for ever, waiting for the `Handshake()`s to return in both the server and the client goroutines.

I poked around a bit by introducing a timeout and noticed that the client reader contains the following bytes sitting around, waiting to be read:

Client: n=7 bytes=[21 3 3 0 2 2 42]

These bytes translate to: TLS record type alert `recordTypeAlert` (21), Version TLS 1.2 (3 3), message length `2`, alert type `alertLevelError` (2) and alert reason `alertBadCertificate` (42).

This is the exact error an HTTPS server would have returned if I had set this test up using `net/http/httptest`.

So my question is, why do the client and server goroutines hang here? Shouldn't these bytes be read and interpreted returning the error to the callers? 

Is this a bug?



--
Cheers,
Madhu

Aliaksandr Valialkin

unread,
Aug 17, 2016, 1:14:40 PM8/17/16
to golang-nuts
Hi, Madhu,

Writes to net.Pipe connections are synchronous - i.e. call to Write returns only after the corresponding call to Read on the other end of pipe is made. TLS implementation in Go may deadlock on net.Pipe connection, since both server and client may call Write on both ends of pipe while nobody calls Read.

Possible workarounds:
1) Wrap read sides of the net.Pipe into an 'eager' io.Reader implementation, which will instantly read all the incoming data into internal buffer until external caller will consume buffered data.
2) Use another net.Pipe-like solution, which already solves the problem. See, for instance, https://godoc.org/github.com/valyala/fasthttp/fasthttputil#PipeConns .

Madhusudan C.S

unread,
Aug 17, 2016, 5:54:41 PM8/17/16
to golang-nuts
Hi Aliaksandr,

Thank you very much for these insights. This helped me understand what's going on.

Also, thanks for the pointers to possible workarounds!
Reply all
Reply to author
Forward
0 new messages