Skip to content

proposal: crypto/tls: add Conn.PeekHandshake #24401

Description

@bradfitz

I was looking at ways to fix #23689 (making net/http respond nicely to clear-text HTTP clients sending requests to HTTPS servers) and of the many possible ways to fix it, most are gross.

You would think that https://golang.org/pkg/crypto/tls/#RecordHeaderError as returned by https://golang.org/pkg/crypto/tls/#Conn.Handshake would be sufficient, but Handshake sends a record alert error to the client before returning, so the connection already has binary gibberish written on it (as far as the HTTP/1.x plaintext client is concerned).

The options I didn't like:

  • I don't really want to make crypto/tls aware of HTTP semantics.
  • I don't want to add a HandshakeOptions
  • I don't want to add a hook to Conn or Handshake to alter alert-sending behavior based on the content
  • Writing an alternate net.Listener or net.Conn wrapper type doesn't help, because net/http accepts any ol' net.Listener and then type-checks the responses for *tls.Conns. (please avoid talking about making that an interface in this bug)
  • exposing tls.Conn's underlying Conn, even with a bunch of documented warnings.

The only thing non-offensive way I can see to fix this is to add:

package tls

// PeekHandshake can be called before a handshake to return some number of bytes from the
// the underlying net.Conn, before the handshake is processed. The bytes should not be mutated
// or retained, and PeekHandshake should not be called concurrently with any other operations.
func (c *Conn) PeekHandshake() ([]byte, error) { ... }

Then net/http can call PeekHandshake before its Handshake and see if it starts with GET or HEAD or POST, etc, and return a nice 400 message.

Open to naming suggestions.

/cc @FiloSottile @agl

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions