diff options
Diffstat (limited to 'libgo/go/crypto/tls/tls.go')
-rw-r--r-- | libgo/go/crypto/tls/tls.go | 106 |
1 files changed, 92 insertions, 14 deletions
diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go index af44485f44e..454aa0bbbc0 100644 --- a/libgo/go/crypto/tls/tls.go +++ b/libgo/go/crypto/tls/tls.go @@ -13,6 +13,7 @@ package tls import ( "bytes" + "context" "crypto" "crypto/ecdsa" "crypto/ed25519" @@ -32,7 +33,12 @@ import ( // The configuration config must be non-nil and must include // at least one certificate or else set GetCertificate. func Server(conn net.Conn, config *Config) *Conn { - return &Conn{conn: conn, config: config} + c := &Conn{ + conn: conn, + config: config, + } + c.handshakeFn = c.serverHandshake + return c } // Client returns a new TLS client side connection @@ -40,7 +46,13 @@ func Server(conn net.Conn, config *Config) *Conn { // The config cannot be nil: users must set either ServerName or // InsecureSkipVerify in the config. func Client(conn net.Conn, config *Config) *Conn { - return &Conn{conn: conn, config: config, isClient: true} + c := &Conn{ + conn: conn, + config: config, + isClient: true, + } + c.handshakeFn = c.clientHandshake + return c } // A listener implements a network listener (net.Listener) for TLS connections. @@ -100,29 +112,35 @@ func (timeoutError) Temporary() bool { return true } // DialWithDialer interprets a nil configuration as equivalent to the zero // configuration; see the documentation of Config for the defaults. func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { + return dial(context.Background(), dialer, network, addr, config) +} + +func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) { // We want the Timeout and Deadline values from dialer to cover the // whole process: TCP connection and TLS handshake. This means that we // also need to start our own timers now. - timeout := dialer.Timeout + timeout := netDialer.Timeout - if !dialer.Deadline.IsZero() { - deadlineTimeout := time.Until(dialer.Deadline) + if !netDialer.Deadline.IsZero() { + deadlineTimeout := time.Until(netDialer.Deadline) if timeout == 0 || deadlineTimeout < timeout { timeout = deadlineTimeout } } - var errChannel chan error - + // hsErrCh is non-nil if we might not wait for Handshake to complete. + var hsErrCh chan error + if timeout != 0 || ctx.Done() != nil { + hsErrCh = make(chan error, 2) + } if timeout != 0 { - errChannel = make(chan error, 2) timer := time.AfterFunc(timeout, func() { - errChannel <- timeoutError{} + hsErrCh <- timeoutError{} }) defer timer.Stop() } - rawConn, err := dialer.Dial(network, addr) + rawConn, err := netDialer.DialContext(ctx, network, addr) if err != nil { return nil, err } @@ -147,14 +165,26 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (* conn := Client(rawConn, config) - if timeout == 0 { + if hsErrCh == nil { err = conn.Handshake() } else { go func() { - errChannel <- conn.Handshake() + hsErrCh <- conn.Handshake() }() - err = <-errChannel + select { + case <-ctx.Done(): + err = ctx.Err() + case err = <-hsErrCh: + if err != nil { + // If the error was due to the context + // closing, prefer the context's error, rather + // than some random network teardown error. + if e := ctx.Err(); e != nil { + err = e + } + } + } } if err != nil { @@ -175,6 +205,54 @@ func Dial(network, addr string, config *Config) (*Conn, error) { return DialWithDialer(new(net.Dialer), network, addr, config) } +// Dialer dials TLS connections given a configuration and a Dialer for the +// underlying connection. +type Dialer struct { + // NetDialer is the optional dialer to use for the TLS connections' + // underlying TCP connections. + // A nil NetDialer is equivalent to the net.Dialer zero value. + NetDialer *net.Dialer + + // Config is the TLS configuration to use for new connections. + // A nil configuration is equivalent to the zero + // configuration; see the documentation of Config for the + // defaults. + Config *Config +} + +// Dial connects to the given network address and initiates a TLS +// handshake, returning the resulting TLS connection. +// +// The returned Conn, if any, will always be of type *Conn. +func (d *Dialer) Dial(network, addr string) (net.Conn, error) { + return d.DialContext(context.Background(), network, addr) +} + +func (d *Dialer) netDialer() *net.Dialer { + if d.NetDialer != nil { + return d.NetDialer + } + return new(net.Dialer) +} + +// DialContext connects to the given network address and initiates a TLS +// handshake, returning the resulting TLS connection. +// +// The provided Context must be non-nil. If the context expires before +// the connection is complete, an error is returned. Once successfully +// connected, any expiration of the context will not affect the +// connection. +// +// The returned Conn, if any, will always be of type *Conn. +func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + c, err := dial(ctx, d.netDialer(), network, addr, d.Config) + if err != nil { + // Don't return c (a typed nil) in an interface. + return nil, err + } + return c, nil +} + // LoadX509KeyPair reads and parses a public/private key pair from a pair // of files. The files must contain PEM encoded data. The certificate file // may contain intermediate certificates following the leaf certificate to @@ -287,7 +365,7 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { } // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates -// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. +// PKCS #1 private keys by default, while OpenSSL 1.0.0 generates PKCS #8 keys. // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { |