Skip to content

Commit c9b9cd7

Browse files
committed
crypto/tls: set Deadline before sending close notify alert
This change also documents the need to set a Deadline before calling Read or Write. Fixes #31224 Change-Id: I89d6fe3ecb0a0076b4c61765f61c88056f951406 Reviewed-on: https://go-review.googlesource.com/c/go/+/266037 Trust: Katie Hockman <[email protected]> Run-TryBot: Katie Hockman <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]>
1 parent f7ef5ca commit c9b9cd7

File tree

2 files changed

+26
-6
lines changed

2 files changed

+26
-6
lines changed

doc/go1.16.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,18 @@ <h3 id="crypto/tls"><a href="/pkg/crypto/tls">crypto/tls</a></h3>
237237

238238
<p><!-- CL 256897 -->
239239
I/O operations on closing or closed TLS connections can now be detected using
240-
the new <a href="/pkg/net/#ErrClosed">ErrClosed</a> error. A typical use
241-
would be <code>errors.Is(err, net.ErrClosed)</code>. In earlier releases
240+
the new <a href="/pkg/net/#ErrClosed">ErrClosed</a> error. A typical use
241+
would be <code>errors.Is(err, net.ErrClosed)</code>. In earlier releases
242242
the only way to reliably detect this case was to match the string returned
243243
by the <code>Error</code> method with <code>"tls: use of closed connection"</code>.
244244
</p>
245245

246+
<p><!-- CL 266037 -->
247+
A default deadline is set in <a href="/pkg/crypto/tls/#Conn.Close">Close</a>
248+
before sending the close notify alert, in order to prevent blocking
249+
indefinitely.
250+
</p>
251+
246252
<h3 id="crypto/x509"><a href="/pkg/crypto/x509">crypto/x509</a></h3>
247253

248254
<p><!-- CL 235078 -->

src/crypto/tls/conn.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,11 @@ var (
10741074
)
10751075

10761076
// Write writes data to the connection.
1077+
//
1078+
// As Write calls Handshake, in order to prevent indefinite blocking a deadline
1079+
// must be set for both Read and Write before Write is called when the handshake
1080+
// has not yet completed. See SetDeadline, SetReadDeadline, and
1081+
// SetWriteDeadline.
10771082
func (c *Conn) Write(b []byte) (int, error) {
10781083
// interlock with Close below
10791084
for {
@@ -1232,8 +1237,12 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
12321237
return nil
12331238
}
12341239

1235-
// Read can be made to time out and return a net.Error with Timeout() == true
1236-
// after a fixed time limit; see SetDeadline and SetReadDeadline.
1240+
// Read reads data from the connection.
1241+
//
1242+
// As Read calls Handshake, in order to prevent indefinite blocking a deadline
1243+
// must be set for both Read and Write before Read is called when the handshake
1244+
// has not yet completed. See SetDeadline, SetReadDeadline, and
1245+
// SetWriteDeadline.
12371246
func (c *Conn) Read(b []byte) (int, error) {
12381247
if err := c.Handshake(); err != nil {
12391248
return 0, err
@@ -1301,9 +1310,10 @@ func (c *Conn) Close() error {
13011310
}
13021311

13031312
var alertErr error
1304-
13051313
if c.handshakeComplete() {
1306-
alertErr = c.closeNotify()
1314+
if err := c.closeNotify(); err != nil {
1315+
alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err)
1316+
}
13071317
}
13081318

13091319
if err := c.conn.Close(); err != nil {
@@ -1330,8 +1340,12 @@ func (c *Conn) closeNotify() error {
13301340
defer c.out.Unlock()
13311341

13321342
if !c.closeNotifySent {
1343+
// Set a Write Deadline to prevent possibly blocking forever.
1344+
c.SetWriteDeadline(time.Now().Add(time.Second * 5))
13331345
c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
13341346
c.closeNotifySent = true
1347+
// Any subsequent writes will fail.
1348+
c.SetWriteDeadline(time.Now())
13351349
}
13361350
return c.closeNotifyErr
13371351
}

0 commit comments

Comments
 (0)