net/http ListenAndServeTLS where are the SSL negotiation errors

556 views
Skip to first unread message

Nick Craig-Wood

unread,
Feb 27, 2014, 8:13:02 AM2/27/14
to golang-nuts
I've been trying to debug some SSL connection problems when using
net/http ListenAndServeTLS.

However any errors in the SSL negotiation just seem to disappear into
the void - no errors are returned and nothing is logged and my ServeMux
is never called.

I've attempted to trace exactly where the errors are going but I can't
see in net/http or crypto/tls anywhere where errors are dropped or a
place I could put an error handler.

Can anyone help?

Thanks
--
Nick Craig-Wood <ni...@craig-wood.com> -- http://www.craig-wood.com/nick

Brad Fitzpatrick

unread,
Feb 27, 2014, 2:00:18 PM2/27/14
to Nick Craig-Wood, golang-nuts, Adam Langley
I would read crypto/tls.NewListener and net/http.Server.Serve

From my quick refresher reading now, the crypto/tls Listener raises no TLS-related failures at accept-time.  The first error won't happen until the first read.

The first read in net/http's Server is in *conn.serve: http://golang.org/src/pkg/net/http/server.go?s=30995:31017#L1078

        for {
              w, err := c.readRequest()
                if err != nil {
               if err == errTooLarge {
                                // Their HTTP client may or may not be
               // able to read this if we're
                                // responding to them and hanging up
                                // while they're still writing their
                                // request.  Undefined behavior.
io.WriteString(c.rwc, "HTTP/1.1 413 Request Entity Too Large\r\n\r\n")
                                c.closeWriteAndWait()
                       break
                        } else if err == io.EOF {
                                break // Don't reply
                        } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
break // Don't reply
                        }
                        io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\n\r\n")
                        break
                }

So yes, if there's a TLS handshake error on the server, we'll write back "HTTP/1.1 400 Bad Request" to the socket, but they'll almost certainly not see it, if they failed to handshake correctly.

Please file a bug about this and copy me and a...@golang.org.  There's probably something better we could do.





--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Nick Craig-Wood

unread,
Feb 27, 2014, 4:11:25 PM2/27/14
to Brad Fitzpatrick, golang-nuts, Adam Langley
On 27/02/14 19:00, Brad Fitzpatrick wrote:
> I would read crypto/tls.NewListener and net/http.Server.Serve
>
> From my quick refresher reading now, the crypto/tls Listener raises no
> TLS-related failures at accept-time. The first error won't happen until
> the first read.
[snip]
> Please file a bug about this and copy me and a...@golang.org
> <mailto:a...@golang.org>. There's probably something better we could do.

There seems to be a report about this already

https://code.google.com/p/go/issues/detail?id=7291

Which suggests the problem is the tlsConn.Handshake returning on error
without reporting it anywhere. There isn't a channel to return it at
that moment - a log.Printf would be helpful for debugging but might
not be the right thing to do.

http://golang.org/src/pkg/net/http/server.go?s=30995:31017#L1108

if tlsConn, ok := c.rwc.(*tls.Conn); ok {
if d := c.server.ReadTimeout; d != 0 {
c.rwc.SetReadDeadline(time.Now().Add(d))
}
if d := c.server.WriteTimeout; d != 0 {
c.rwc.SetWriteDeadline(time.Now().Add(d))
}
if err := tlsConn.Handshake(); err != nil {
// A log.Printf would be really helpful here!
return
}
c.tlsState = new(tls.ConnectionState)
*c.tlsState = tlsConn.ConnectionState()
if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) {
if fn := c.server.TLSNextProto[proto]; fn != nil {
h := initNPNRequest{tlsConn, serverHandler{c.server}}
fn(c.server, tlsConn, h)
}
return
Reply all
Reply to author
Forward
0 new messages