indefinitely.
 </p>
 
+<p><!-- CL 246338 -->
+  <a href="/pkg/crypto/tls#Conn.HandshakeContext">(*Conn).HandshakeContext</a> was added to
+  allow the user to control cancellation of an in-progress TLS Handshake.
+  The context provided is propagated into the
+  <a href="/pkg/crypto/tls#ClientHelloInfo">ClientHelloInfo</a>
+  and <a href="/pkg/crypto/tls#CertificateRequestInfo">CertificateRequestInfo</a>
+  structs and accessible through the new
+  <a href="/pkg/crypto/tls#ClientHelloInfo.Context">(*ClientHelloInfo).Context</a>
+  and
+  <a href="/pkg/crypto/tls#CertificateRequestInfo.Context">
+    (*CertificateRequestInfo).Context
+  </a> methods respectively. Canceling the context after the handshake has finished
+  has no effect.
+</p>
+
 <h3 id="crypto/x509"><a href="/pkg/crypto/x509">crypto/x509</a></h3>
 
 <p><!-- CL 235078 -->
     Cookies set with <code>SameSiteDefaultMode</code> now behave according to the current
     spec (no attribute is set) instead of generating a SameSite key without a value.
     </p>
+
+    <p><!-- CL 246338 -->
+      The <a href="/pkg/net/http/"><code>net/http</code></a> package now uses the new
+      <a href="/pkg/crypto/tls#Conn.HandshakeContext"><code>(*tls.Conn).HandshakeContext</code></a>
+      with the <a href="/pkg/net/http/#Request"><code>Request</code></a> context
+      when performing TLS handshakes in the client or server.
+    </p>
   </dd>
 </dl><!-- net/http -->
 
 
 import (
        "bytes"
        "container/list"
+       "context"
        "crypto"
        "crypto/ecdsa"
        "crypto/ed25519"
        // config is embedded by the GetCertificate or GetConfigForClient caller,
        // for use with SupportsCertificate.
        config *Config
+
+       // ctx is the context of the handshake that is in progress.
+       ctx context.Context
+}
+
+// Context returns the context of the handshake that is in progress.
+// This context is a child of the context passed to HandshakeContext,
+// if any, and is canceled when the handshake concludes.
+func (c *ClientHelloInfo) Context() context.Context {
+       return c.ctx
 }
 
 // CertificateRequestInfo contains information from a server's
 
        // Version is the TLS version that was negotiated for this connection.
        Version uint16
+
+       // ctx is the context of the handshake that is in progress.
+       ctx context.Context
+}
+
+// Context returns the context of the handshake that is in progress.
+// This context is a child of the context passed to HandshakeContext,
+// if any, and is canceled when the handshake concludes.
+func (c *CertificateRequestInfo) Context() context.Context {
+       return c.ctx
 }
 
 // RenegotiationSupport enumerates the different levels of support for TLS
 
 
 import (
        "bytes"
+       "context"
        "crypto/cipher"
        "crypto/subtle"
        "crypto/x509"
        // constant
        conn        net.Conn
        isClient    bool
-       handshakeFn func() error // (*Conn).clientHandshake or serverHandshake
+       handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake
 
        // handshakeStatus is 1 if the connection is currently transferring
        // application data (i.e. is not currently processing a handshake).
        defer c.handshakeMutex.Unlock()
 
        atomic.StoreUint32(&c.handshakeStatus, 0)
-       if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil {
+       if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil {
                c.handshakes++
        }
        return c.handshakeErr
 // first Read or Write will call it automatically.
 //
 // For control over canceling or setting a timeout on a handshake, use
-// the Dialer's DialContext method.
+// HandshakeContext or the Dialer's DialContext method instead.
 func (c *Conn) Handshake() error {
+       return c.HandshakeContext(context.Background())
+}
+
+// HandshakeContext runs the client or server handshake
+// protocol if it has not yet been run.
+//
+// The provided Context must be non-nil. If the context is canceled before
+// the handshake is complete, the handshake is interrupted and an error is returned.
+// Once the handshake has completed, cancellation of the context will not affect the
+// connection.
+//
+// Most uses of this package need not call HandshakeContext explicitly: the
+// first Read or Write will call it automatically.
+func (c *Conn) HandshakeContext(ctx context.Context) error {
+       // Delegate to unexported method for named return
+       // without confusing documented signature.
+       return c.handshakeContext(ctx)
+}
+
+func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
+       handshakeCtx, cancel := context.WithCancel(ctx)
+       // Note: defer this before starting the "interrupter" goroutine
+       // so that we can tell the difference between the input being canceled and
+       // this cancellation. In the former case, we need to close the connection.
+       defer cancel()
+
+       // Start the "interrupter" goroutine, if this context might be canceled.
+       // (The background context cannot).
+       //
+       // The interrupter goroutine waits for the input context to be done and
+       // closes the connection if this happens before the function returns.
+       if ctx.Done() != nil {
+               done := make(chan struct{})
+               interruptRes := make(chan error, 1)
+               defer func() {
+                       close(done)
+                       if ctxErr := <-interruptRes; ctxErr != nil {
+                               // Return context error to user.
+                               ret = ctxErr
+                       }
+               }()
+               go func() {
+                       select {
+                       case <-handshakeCtx.Done():
+                               // Close the connection, discarding the error
+                               _ = c.conn.Close()
+                               interruptRes <- handshakeCtx.Err()
+                       case <-done:
+                               interruptRes <- nil
+                       }
+               }()
+       }
+
        c.handshakeMutex.Lock()
        defer c.handshakeMutex.Unlock()
 
        c.in.Lock()
        defer c.in.Unlock()
 
-       c.handshakeErr = c.handshakeFn()
+       c.handshakeErr = c.handshakeFn(handshakeCtx)
        if c.handshakeErr == nil {
                c.handshakes++
        } else {
 
 
 import (
        "bytes"
+       "context"
        "crypto"
        "crypto/ecdsa"
        "crypto/ed25519"
 
 type clientHandshakeState struct {
        c            *Conn
+       ctx          context.Context
        serverHello  *serverHelloMsg
        hello        *clientHelloMsg
        suite        *cipherSuite
        return hello, params, nil
 }
 
-func (c *Conn) clientHandshake() (err error) {
+func (c *Conn) clientHandshake(ctx context.Context) (err error) {
        if c.config == nil {
                c.config = defaultConfig()
        }
        if c.vers == VersionTLS13 {
                hs := &clientHandshakeStateTLS13{
                        c:           c,
+                       ctx:         ctx,
                        serverHello: serverHello,
                        hello:       hello,
                        ecdheParams: ecdheParams,
 
        hs := &clientHandshakeState{
                c:           c,
+               ctx:         ctx,
                serverHello: serverHello,
                hello:       hello,
                session:     session,
                certRequested = true
                hs.finishedHash.Write(certReq.marshal())
 
-               cri := certificateRequestInfoFromMsg(c.vers, certReq)
+               cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
                if chainToSend, err = c.getClientCertificate(cri); err != nil {
                        c.sendAlert(alertInternalError)
                        return err
 
 // certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
 // <= 1.2 CertificateRequest, making an effort to fill in missing information.
-func certificateRequestInfoFromMsg(vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
+func certificateRequestInfoFromMsg(ctx context.Context, vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
        cri := &CertificateRequestInfo{
                AcceptableCAs: certReq.certificateAuthorities,
                Version:       vers,
+               ctx:           ctx,
        }
 
        var rsaAvail, ecAvail bool
 
 
 import (
        "bytes"
+       "context"
        "crypto/rsa"
        "crypto/x509"
        "encoding/base64"
        "os/exec"
        "path/filepath"
        "reflect"
+       "runtime"
        "strconv"
        "strings"
        "testing"
                        serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps)
        }
 }
+
+func TestClientHandshakeContextCancellation(t *testing.T) {
+       c, s := localPipe(t)
+       serverConfig := testConfig.Clone()
+       serverErr := make(chan error, 1)
+       ctx, cancel := context.WithCancel(context.Background())
+       defer cancel()
+       go func() {
+               defer close(serverErr)
+               defer s.Close()
+               conn := Server(s, serverConfig)
+               _, err := conn.readClientHello(ctx)
+               cancel()
+               serverErr <- err
+       }()
+       cli := Client(c, testConfig)
+       err := cli.HandshakeContext(ctx)
+       if err == nil {
+               t.Fatal("Client handshake did not error when the context was canceled")
+       }
+       if err != context.Canceled {
+               t.Errorf("Unexpected client handshake error: %v", err)
+       }
+       if err := <-serverErr; err != nil {
+               t.Errorf("Unexpected server error: %v", err)
+       }
+       if runtime.GOARCH == "wasm" {
+               t.Skip("conn.Close does not error as expected when called multiple times on WASM")
+       }
+       err = cli.Close()
+       if err == nil {
+               t.Error("Client connection was not closed when the context was canceled")
+       }
+}
 
 
 import (
        "bytes"
+       "context"
        "crypto"
        "crypto/hmac"
        "crypto/rsa"
 
 type clientHandshakeStateTLS13 struct {
        c           *Conn
+       ctx         context.Context
        serverHello *serverHelloMsg
        hello       *clientHelloMsg
        ecdheParams ecdheParameters
                AcceptableCAs:    hs.certReq.certificateAuthorities,
                SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
                Version:          c.vers,
+               ctx:              hs.ctx,
        })
        if err != nil {
                return err
 
 package tls
 
 import (
+       "context"
        "crypto"
        "crypto/ecdsa"
        "crypto/ed25519"
 // It's discarded once the handshake has completed.
 type serverHandshakeState struct {
        c            *Conn
+       ctx          context.Context
        clientHello  *clientHelloMsg
        hello        *serverHelloMsg
        suite        *cipherSuite
 }
 
 // serverHandshake performs a TLS handshake as a server.
-func (c *Conn) serverHandshake() error {
-       clientHello, err := c.readClientHello()
+func (c *Conn) serverHandshake(ctx context.Context) error {
+       clientHello, err := c.readClientHello(ctx)
        if err != nil {
                return err
        }
        if c.vers == VersionTLS13 {
                hs := serverHandshakeStateTLS13{
                        c:           c,
+                       ctx:         ctx,
                        clientHello: clientHello,
                }
                return hs.handshake()
 
        hs := serverHandshakeState{
                c:           c,
+               ctx:         ctx,
                clientHello: clientHello,
        }
        return hs.handshake()
 }
 
 // readClientHello reads a ClientHello message and selects the protocol version.
-func (c *Conn) readClientHello() (*clientHelloMsg, error) {
+func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
        msg, err := c.readHandshake()
        if err != nil {
                return nil, err
        var configForClient *Config
        originalConfig := c.config
        if c.config.GetConfigForClient != nil {
-               chi := clientHelloInfo(c, clientHello)
+               chi := clientHelloInfo(ctx, c, clientHello)
                if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
                        c.sendAlert(alertInternalError)
                        return nil, err
                }
        }
 
-       hs.cert, err = c.config.getCertificate(clientHelloInfo(c, hs.clientHello))
+       hs.cert, err = c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello))
        if err != nil {
                if err == errNoCertificates {
                        c.sendAlert(alertUnrecognizedName)
        return nil
 }
 
-func clientHelloInfo(c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
+func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
        supportedVersions := clientHello.supportedVersions
        if len(clientHello.supportedVersions) == 0 {
                supportedVersions = supportedVersionsFromMax(clientHello.vers)
                SupportedVersions: supportedVersions,
                Conn:              c.conn,
                config:            c.config,
+               ctx:               ctx,
        }
 }
 
 
 import (
        "bytes"
+       "context"
        "crypto"
        "crypto/elliptic"
        "crypto/x509"
        "os"
        "os/exec"
        "path/filepath"
+       "runtime"
        "strings"
        "testing"
        "time"
                cli.writeRecord(recordTypeHandshake, m.marshal())
                c.Close()
        }()
+       ctx := context.Background()
        conn := Server(s, serverConfig)
-       ch, err := conn.readClientHello()
+       ch, err := conn.readClientHello(ctx)
        hs := serverHandshakeState{
                c:           conn,
+               ctx:         ctx,
                clientHello: ch,
        }
        if err == nil {
                c.Close()
        }()
        conn := Server(s, serverConfig)
-       ch, err := conn.readClientHello()
+       ctx := context.Background()
+       ch, err := conn.readClientHello(ctx)
        hs := serverHandshakeState{
                c:           conn,
+               ctx:         ctx,
                clientHello: ch,
        }
        if err == nil {
                t.Errorf("expected RSA certificate, got %v", got)
        }
 }
+
+func TestServerHandshakeContextCancellation(t *testing.T) {
+       c, s := localPipe(t)
+       clientConfig := testConfig.Clone()
+       clientErr := make(chan error, 1)
+       ctx, cancel := context.WithCancel(context.Background())
+       defer cancel()
+       go func() {
+               defer close(clientErr)
+               defer c.Close()
+               clientHello := &clientHelloMsg{
+                       vers:               VersionTLS10,
+                       random:             make([]byte, 32),
+                       cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+                       compressionMethods: []uint8{compressionNone},
+               }
+               cli := Client(c, clientConfig)
+               _, err := cli.writeRecord(recordTypeHandshake, clientHello.marshal())
+               cancel()
+               clientErr <- err
+       }()
+       conn := Server(s, testConfig)
+       err := conn.HandshakeContext(ctx)
+       if err == nil {
+               t.Fatal("Server handshake did not error when the context was canceled")
+       }
+       if err != context.Canceled {
+               t.Errorf("Unexpected server handshake error: %v", err)
+       }
+       if err := <-clientErr; err != nil {
+               t.Errorf("Unexpected client error: %v", err)
+       }
+       if runtime.GOARCH == "wasm" {
+               t.Skip("conn.Close does not error as expected when called multiple times on WASM")
+       }
+       err = conn.Close()
+       if err == nil {
+               t.Error("Server connection was not closed when the context was canceled")
+       }
+}
 
 
 import (
        "bytes"
+       "context"
        "crypto"
        "crypto/hmac"
        "crypto/rsa"
 
 type serverHandshakeStateTLS13 struct {
        c               *Conn
+       ctx             context.Context
        clientHello     *clientHelloMsg
        hello           *serverHelloMsg
        sentDummyCCS    bool
                return c.sendAlert(alertMissingExtension)
        }
 
-       certificate, err := c.config.getCertificate(clientHelloInfo(c, hs.clientHello))
+       certificate, err := c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello))
        if err != nil {
                if err == errNoCertificates {
                        c.sendAlert(alertUnrecognizedName)
 
        "io/ioutil"
        "net"
        "strings"
-       "time"
 )
 
 // Server returns a new TLS server side connection
 }
 
 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 := netDialer.Timeout
-
-       if !netDialer.Deadline.IsZero() {
-               deadlineTimeout := time.Until(netDialer.Deadline)
-               if timeout == 0 || deadlineTimeout < timeout {
-                       timeout = deadlineTimeout
-               }
+       if netDialer.Timeout != 0 {
+               var cancel context.CancelFunc
+               ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout)
+               defer cancel()
        }
 
-       // 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 {
-               timer := time.AfterFunc(timeout, func() {
-                       hsErrCh <- timeoutError{}
-               })
-               defer timer.Stop()
+       if !netDialer.Deadline.IsZero() {
+               var cancel context.CancelFunc
+               ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline)
+               defer cancel()
        }
 
        rawConn, err := netDialer.DialContext(ctx, network, addr)
        }
 
        conn := Client(rawConn, config)
-
-       if hsErrCh == nil {
-               err = conn.Handshake()
-       } else {
-               go func() {
-                       hsErrCh <- conn.Handshake()
-               }()
-
-               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 {
+       if err := conn.HandshakeContext(ctx); err != nil {
                rawConn.Close()
                return nil, err
        }
-
        return conn, nil
 }
 
 
                if d := c.server.WriteTimeout; d != 0 {
                        c.rwc.SetWriteDeadline(time.Now().Add(d))
                }
-               if err := tlsConn.Handshake(); err != nil {
+               if err := tlsConn.HandshakeContext(ctx); err != nil {
                        // If the handshake failed due to the client not speaking
                        // TLS, assume they're speaking plaintext HTTP and write a
                        // 400 response on the TLS conn's underlying net.Conn.
 
 // Add TLS to a persistent connection, i.e. negotiate a TLS session. If pconn is already a TLS
 // tunnel, this function establishes a nested TLS session inside the encrypted channel.
 // The remote endpoint's name may be overridden by TLSClientConfig.ServerName.
-func (pconn *persistConn) addTLS(name string, trace *httptrace.ClientTrace) error {
+func (pconn *persistConn) addTLS(ctx context.Context, name string, trace *httptrace.ClientTrace) error {
        // Initiate TLS and check remote host name against certificate.
        cfg := cloneTLSConfig(pconn.t.TLSClientConfig)
        if cfg.ServerName == "" {
                if trace != nil && trace.TLSHandshakeStart != nil {
                        trace.TLSHandshakeStart()
                }
-               err := tlsConn.Handshake()
+               err := tlsConn.HandshakeContext(ctx)
                if timer != nil {
                        timer.Stop()
                }
                        if trace != nil && trace.TLSHandshakeStart != nil {
                                trace.TLSHandshakeStart()
                        }
-                       if err := tc.Handshake(); err != nil {
+                       if err := tc.HandshakeContext(ctx); err != nil {
                                go pconn.conn.Close()
                                if trace != nil && trace.TLSHandshakeDone != nil {
                                        trace.TLSHandshakeDone(tls.ConnectionState{}, err)
                        if firstTLSHost, _, err = net.SplitHostPort(cm.addr()); err != nil {
                                return nil, wrapErr(err)
                        }
-                       if err = pconn.addTLS(firstTLSHost, trace); err != nil {
+                       if err = pconn.addTLS(ctx, firstTLSHost, trace); err != nil {
                                return nil, wrapErr(err)
                        }
                }
        }
 
        if cm.proxyURL != nil && cm.targetScheme == "https" {
-               if err := pconn.addTLS(cm.tlsHost(), trace); err != nil {
+               if err := pconn.addTLS(ctx, cm.tlsHost(), trace); err != nil {
                        return nil, err
                }
        }
 
                if err != nil {
                        return nil, err
                }
-               return c, c.Handshake()
+               return c, c.HandshakeContext(ctx)
        }
 
        req, err := NewRequest("GET", ts.URL, nil)