Skip to content

proposal: net/http: allow use of external TLS stacks #21753

Closed
@FiloSottile

Description

@FiloSottile

net/http is hardcoded to work with crypto/tls, and it's currently impossible to use any other TLS stack. That meant that for example to develop the tls-tris fork of crypto/tls with TLS 1.3 support I had to do horrible things which made life pretty hard for other developers on the project.

@rsc mentioned he'd be interested in making it possible to use non-crypto/tls stacks with net/http. While I don't think we should necessarily encourage it (it's good that "what TLS stack do I want?" is not a question a Go developer has to ask themselves), I agree it would be nice to at least make it possible.

Here's a survey of the coupling points, and proposals on how to fix (most) of them.

/cc @agl @bradfitz @rsc @mholt

Server side

  • Request.TLS has type *tls.ConnectionState
    • I think it's acceptable to require external stacks to use the crypto/tls ConnectionState type
  • serve type-asserts *tls.Conn to detect a TLS connection and call Handshake() and ConnectionState()
    • Here we can type-assert to an (probably unexported) interface with those two methods
  • Server.TLSNextProto has type map[string]func(*Server, *tls.Conn, Handler)
    • This is a problem: the function here will have to work with the concrete *tls.Conn, and there is code out there written with this assumption, including the standard http2 library
  • ServeTLS and ListenAndServeTLS
    • These are helpers, no reason they shouldn't use crypto/tls
  • Server.TLSConfig has type *tls.Config
    • We can mostly ignore this, as it's only used for ServeTLS/ListenAndServeTLS and for some auto-HTTP/2 logic

Client side

  • Client asserts tls.RecordHeaderError to detect a mistaken plain HTTP response
    • External stacks can just use the crypto/tls error type
  • Response.TLS has type *tls.ConnectionState
    • As above, it's acceptable to require external stacks to use the crypto/tls ConnectionState type
  • Transport.TLSClientConfig has type *tls.Config
    • We can ignore this, as it can be overridden with DialTLS, so it's basically part of a helper
  • Auto-HTTP/2 is disabled by DialTLS being set
    • I think the client logic should be more like the server one, where the HTTP stack is configured if the TLS state is unknown (t.DialTLS != nil) or the TLS Config is available (t.TLSClientConfig != nil) and h2 is enabled (this might be a separate issue)
  • Transport.TLSNextProto has type map[string]func(authority string, c *tls.Conn) RoundTripper
    • Like Server.TLSNextProto, this is a problem
  • dialConn type-asserts *tls.Conn
    • Like above, we can instead assert an interface

Conclusion

The main problem are the two TLSNextProto, for which I have no good solution. The auto-HTTP/2 logic might also need attention. Other parts can be either ignored as helpers, or discreetly fixed.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions