tls-socket: Change how EOF of the underlying socket is handled
authorTobias Brunner <tobias@strongswan.org>
Fri, 28 Aug 2020 09:56:36 +0000 (11:56 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 12 Feb 2021 10:45:44 +0000 (11:45 +0100)
With the previous code, there was an issue when replying to TLS 1.3
post-handshake messages.  In this case, SUCCESS is eventually returned
from build(), however, no actual data has been received so in_done is 0.
This was interpreted as EOF, plain_eof was set to TRUE and no further data
was read from the socket afterwards.

Returning SUCCESS from build() if the exchange is initiated by
write_(), as is the case with the finished reply, never was a problem
because there the return value of 0 is not interpreted as EOF.

src/libtls/tls_socket.c

index 7745988..8b427dd 100644 (file)
@@ -101,6 +101,11 @@ struct private_tls_socket_t {
         * Underlying OS socket
         */
        int fd;
+
+       /**
+        * Whether the socket returned EOF
+        */
+       bool eof;
 };
 
 METHOD(tls_application_t, process, status_t,
@@ -236,6 +241,7 @@ static bool exchange(private_tls_socket_t *this, bool wr, bool block)
                }
                if (in == 0)
                {       /* EOF */
+                       this->eof = TRUE;
                        return TRUE;
                }
                switch (this->tls->process(this->tls, buf, in))
@@ -268,11 +274,20 @@ METHOD(tls_socket_t, read_, ssize_t,
                }
                return cache;
        }
+       if (this->eof)
+       {
+               return 0;
+       }
        this->app.in.ptr = buf;
        this->app.in.len = len;
        this->app.in_done = 0;
        if (exchange(this, FALSE, block))
        {
+               if (!this->app.in_done && !this->eof)
+               {
+                       errno = EWOULDBLOCK;
+                       return -1;
+               }
                return this->app.in_done;
        }
        return -1;
@@ -296,13 +311,13 @@ METHOD(tls_socket_t, splice, bool,
 {
        char buf[PLAIN_BUF_SIZE], *pos;
        ssize_t in, out;
-       bool old, plain_eof = FALSE, crypto_eof = FALSE;
+       bool old, crypto_eof = FALSE;
        struct pollfd pfd[] = {
                { .fd = this->fd,       .events = POLLIN, },
                { .fd = rfd,            .events = POLLIN, },
        };
 
-       while (!plain_eof && !crypto_eof)
+       while (!this->eof && !crypto_eof)
        {
                old = thread_cancelability(TRUE);
                in = poll(pfd, countof(pfd), -1);
@@ -312,14 +327,11 @@ METHOD(tls_socket_t, splice, bool,
                        DBG1(DBG_TLS, "TLS select error: %s", strerror(errno));
                        return FALSE;
                }
-               while (!plain_eof && pfd[0].revents & (POLLIN | POLLHUP | POLLNVAL))
+               while (!this->eof && pfd[0].revents & (POLLIN | POLLHUP | POLLNVAL))
                {
                        in = read_(this, buf, sizeof(buf), FALSE);
                        switch (in)
                        {
-                               case 0:
-                                       plain_eof = TRUE;
-                                       break;
                                case -1:
                                        if (errno != EWOULDBLOCK)
                                        {