Add a test for BIO_read() returning 0 in SSL_read() (and also for write)
authorMatt Caswell <matt@openssl.org>
Thu, 27 Oct 2016 12:46:57 +0000 (13:46 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 28 Oct 2016 08:13:49 +0000 (09:13 +0100)
A BIO_read() 0 return indicates that a failure occurred that may be
retryable. An SSL_read() 0 return indicates a non-retryable failure. Check
that if BIO_read() returns 0, SSL_read() returns <0. Same for SSL_write().

The asyncio test filter BIO already returns 0 on a retryable failure so we
build on that.

Reviewed-by: Richard Levitte <levitte@openssl.org>
test/asynciotest.c

index 720cc7c662c3a8e55b049fe1f33c8ef1880974e1..23d0907dc9151ece990d757e68ff3012bd1d3695 100644 (file)
@@ -234,12 +234,17 @@ static int async_puts(BIO *bio, const char *str)
     return async_write(bio, str, strlen(str));
 }
 
+#define MAX_ATTEMPTS    100
+
 int main(int argc, char *argv[])
 {
     SSL_CTX *serverctx = NULL, *clientctx = NULL;
     SSL *serverssl = NULL, *clientssl = NULL;
     BIO *s_to_c_fbio = NULL, *c_to_s_fbio = NULL;
-    int test, err = 1;
+    int test, err = 1, ret;
+    size_t i, j;
+    const char testdata[] = "Test data";
+    char buf[sizeof(testdata)];
 
     CRYPTO_set_mem_debug(1);
     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
@@ -287,6 +292,42 @@ int main(int argc, char *argv[])
             goto end;
         }
 
+        /*
+         * Send and receive some test data. Do the whole thing twice to ensure
+         * we hit at least one async event in both reading and writing
+         */
+        for (j = 0; j < 2; j++) {
+            /*
+             * Write some test data. It should never take more than 2 attempts
+             * (the first one might be a retryable fail). A zero return from
+             * SSL_write() is a non-retryable failure, so fail immediately if
+             * we get that.
+             */
+            for (ret = -1, i = 0; ret < 0 && i < 2 * sizeof(testdata); i++)
+                ret = SSL_write(clientssl, testdata, sizeof(testdata));
+            if (ret <= 0) {
+                printf("Test %d failed: Failed to write app data\n", test);
+                goto end;
+            }
+            /*
+             * Now read the test data. It may take more attemps here because
+             * it could fail once for each byte read, including all overhead
+             * bytes from the record header/padding etc. Fail immediately if we
+             * get a zero return from SSL_read().
+             */
+            for (ret = -1, i = 0; ret < 0 && i < MAX_ATTEMPTS; i++)
+                ret = SSL_read(serverssl, buf, sizeof(buf));
+            if (ret <= 0) {
+                printf("Test %d failed: Failed to read app data\n", test);
+                goto end;
+            }
+            if (ret != sizeof(testdata)
+                    || memcmp(buf, testdata, sizeof(testdata)) != 0) {
+                printf("Test %d failed: Unexpected app data received\n", test);
+                goto end;
+            }
+        }
+
         /* Also frees the BIOs */
         SSL_free(clientssl);
         SSL_free(serverssl);