Go: crypto/tls: add Dialer with Dial, DialContext methods

Created on 31 Dec 2016  路  23Comments  路  Source: golang/go

In go 1.7, Dialer now has DialContext, which takes a context.Context and uses it for expiration.

However, DialWithDialer just calls Dial on its given Dialer, and doesn't take a context.Context.

To be backwards compatible, probably need to provide a separate function, say, DialContextWithDialer, that is like DialWithDialer except it takes a context.Context and calls DialContext, and have DialWithDialer call DialContextWithDialer with context.Background().

It looks like as a workaround, callers can write their own DialContextWithDialer function and copy most of DialWithDialer.

FeatureRequest NeedsFix Proposal-Accepted

Most helpful comment

Counter proposal:

What if we add a new crypto/tls.Dialer type, with two fields:

// Dialer dials TLS connections given a configuration and a Dialer for the
// underlying connection. 
type Dialer struct {
     Config    *Config
     NetDialer *net.Dialer
}

Then the new Dialer can have Dial and DialContext methods with the normal signatures.

Thoughts?

All 23 comments

The review period for Go 1.7 APIs ended 6 months ago.

The review period for Go 1.8 APIs ended approximately 3 weeks ago.

We can consider something new in crypto/tls for Go 1.9.

For now, you'll just have to dial first, and then use https://golang.org/pkg/crypto/tls/#Client to start the client handshake on the already-connected TCP (or whatever) Conn.

I believe I have a use-case for this feature and would be curious if there's a suggested work-around.

We're trying to configure a http.Transport such that the client does extra validation of the server-provided certificate before sending any data. We want this client to compare server-provided certificate fields against values present on the req.Context. We see Transport.DialContext() but there's no Transport.DialTLSContext(), and setting a DialContext function that does TLS internally looks like it won't work.

Edit: perhaps I'm asking in the wrong issue -- this is bigger than just the crypto/tls package...

Hello! Sorry for "pinging", but will this issue be landed in 1.10? Milestone is 1.10 but no NeedsFix label... Im okay with the work-around, but it looks like little dirty when I need to copy logic of adding tls.Config.ServerName from tls.DialWithDialer().

@gobwas There has been no definite decision to implement this, and there is no patch. At this point I would say that it is unlikely to be fixed for 1.10. Sorry.

Change https://golang.org/cl/93255 mentions this issue: crypto/tls: add DialContextWithDialer function

Is there currently a workaround for this issue?

@maja42 As @akalin-keybase said

It looks like as a workaround, callers can write their own DialContextWithDialer function and copy most of DialWithDialer.

I submitted a patch implementing this a few months ago but I'm not sure if there's a decision to add this to the API.

@bradfitz is there a decision one way or the other?

@FiloSottile, I'm going to remove the Proposal-Crypto review so this gets some attention during the proposal review meetings (which exclude Crypto).

This is more standard library API than it is crypto, and you also seem to be backlogged on other crypto stuff.

Counter proposal:

What if we add a new crypto/tls.Dialer type, with two fields:

// Dialer dials TLS connections given a configuration and a Dialer for the
// underlying connection. 
type Dialer struct {
     Config    *Config
     NetDialer *net.Dialer
}

Then the new Dialer can have Dial and DialContext methods with the normal signatures.

Thoughts?

crypto/tls.Dialer LGTM, with deprecation of crypto/tls.DialWithDialer in favor of crypto/tls.Dialer.Dial.

If this is approved, I'll implement it in the TLS 1.3 dev cycle.

Works for me!

Another possibility: What about adding a context.Context field on tls.Config? This has a few advantages I can see:

  • Doesn't require new methods in crypto/tls
  • Easier to plumb through from net/http, which has a TLSClientConfig field on Transport
  • Allows the context to be applied to handshaking, not just TCP dialing. In Boulder, we just found a connection leak when a remote host times out a handshake.

@jsha, that would violate the context rules of not storing them in long-lived or shared structures, and *tls.Config is generally both.

I don't understand your handshake concern: we already do the handshake under the provided timeout. That wouldn't change with the design proposed above. The handshake would still be under the context's deadline.

@jsha, that would violate the context rules of not storing them in long-lived or shared structures, and *tls.Config is generally both.

Ah, good point. I was looking primarily at the conn.Client method, where *tls.Config is short-lived and non-shared. Is it accurate to say that *tls.Config is short-lived and non-shared when used by a client, but not when used by a server?

I don't understand your handshake concern: we already do the handshake under the provided timeout. That wouldn't change with the design proposed above. The handshake would still be under the context's deadline.

The Handshake concern applies only in code where you build your own TCP connection then hand it off to crypto/tls for the handshake:

netConn, _ := dialer.DialContext(ctx, "tcp", hostPort)
conn := tls.Client(netConn, config) 
conn.Handshake()

It's not strictly related to implementing DialContextWithDialer, but it's another place in crypto/tls that appears to need the context treatment, so I wanted to suggest an idea that might kill two birds with one stone. I'm also happy to file a separate issue about Handshake.

Is it accurate to say that *tls.Config is short-lived and non-shared when used by a client, but not when used by a server?

Nevermind on this; I looked again and realized that yes, clients will typically reuse a *tls.Config many times, though it is not required by the API.

Any progress on this issue ?

Should the methods on tls.Dialer return net.Conn (to match the common signatures) or *tls.Conn?

func (*Dialer) Dial(network, address string) (*Conn, error)
func (*Dialer) DialContext(ctx context.Context, network, address string) (*Conn, error)
func (*Dialer) Dial(network, address string) (net.Conn, error)
func (*Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error)

Also, we should probably allow Dialer.NetDialer to be nil, so DialContext can be used without a custom net.Dialer.

Seeing as the two existing TLS dial functions (tls.Dial and tls.DialWithDialer) both return *tls.Conn, I think these should also return *tls.Conn.

@bradfitz points out that net/http.Transport has function fields that would be type-matched by these methods if we made them return net.Conn instead of *tls.Conn. So probably we should return net.Conn here. We could still document that the underlying type is *tls.Conn.

Otherwise this seems like a likely accept based on the discussion above.

Leaving open for a week for final comments.

(I think that's referring to https://github.com/golang/go/issues/21526 ?)

@rosenhouse, yes, the point is that if this tls.Dialer's Dial and DialContext methods return net.Conn (not *tls.Conn), then you can do assignments like this without adapters:

var d tls.Dialer
var t http.Transport
t.Dial = d.Dial
t.DialContext = d.DialContext

Change https://golang.org/cl/214977 mentions this issue: crypto/tls: add Dialer

No change in consensus, so accepted.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

OneOfOne picture OneOfOne  路  3Comments

jayhuang75 picture jayhuang75  路  3Comments

michaelsafyan picture michaelsafyan  路  3Comments

rakyll picture rakyll  路  3Comments

gopherbot picture gopherbot  路  3Comments