summaryrefslogtreecommitdiff
path: root/libgo/go/crypto/tls/tls.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/crypto/tls/tls.go')
-rw-r--r--libgo/go/crypto/tls/tls.go106
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 {