Ignore EPIPE when sending NewSessionTickets in TLSv1.3
authorMatt Caswell <matt@openssl.org>
Mon, 13 Aug 2018 19:18:32 +0000 (20:18 +0100)
committerMatt Caswell <matt@openssl.org>
Tue, 4 Sep 2018 10:06:48 +0000 (11:06 +0100)
If a client sends data to a server and then immediately closes without
waiting to read the NewSessionTickets then the server can receive EPIPE
when trying to write the tickets and never gets the opportunity to read
the data that was sent. Therefore we ignore EPIPE when writing out the
tickets in TLSv1.3

Fixes #6904

Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6944)

ssl/statem/statem_srvr.c

index db5aafe3be93ca72a6b924157d5fdd716bc18b10..346b1e3989164c27f047a035b459708857534761 100644 (file)
@@ -764,6 +764,22 @@ WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst)
     return WORK_FINISHED_CONTINUE;
 }
 
+static ossl_inline int conn_is_closed(void)
+{
+    switch (get_last_sys_error()) {
+#if defined(EPIPE)
+    case EPIPE:
+        return 1;
+#endif
+#if defined(ECONNRESET)
+    case ECONNRESET:
+        return 1;
+#endif
+    default:
+        return 0;
+    }
+}
+
 /*
  * Perform any work that needs to be done after sending a message from the
  * server to the client.
@@ -939,8 +955,23 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
         break;
 
     case TLS_ST_SW_SESSION_TICKET:
-        if (SSL_IS_TLS13(s) && statem_flush(s) != 1)
+        clear_sys_error();
+        if (SSL_IS_TLS13(s) && statem_flush(s) != 1) {
+            if (SSL_get_error(s, 0) == SSL_ERROR_SYSCALL
+                    && conn_is_closed()) {
+                /*
+                 * We ignore connection closed errors in TLSv1.3 when sending a
+                 * NewSessionTicket and behave as if we were successful. This is
+                 * so that we are still able to read data sent to us by a client
+                 * that closes soon after the end of the handshake without
+                 * waiting to read our post-handshake NewSessionTickets.
+                 */
+                s->rwstate = SSL_NOTHING;
+                break;
+            }
+
             return WORK_MORE_A;
+        }
         break;
     }