Browse Source

Merge pull request #5458 from icing/quic-earlydata

QUIC fixes for handling of early data
David Garske 1 year ago
parent
commit
90c65bd50b
4 changed files with 47 additions and 27 deletions
  1. 42 17
      src/quic.c
  2. 1 1
      src/tls13.c
  3. 3 9
      tests/quic.c
  4. 1 0
      wolfssl/internal.h

+ 42 - 17
src/quic.c

@@ -273,6 +273,7 @@ void wolfSSL_quic_clear(WOLFSSL* ssl)
     }
     ssl->quic.enc_level_write = wolfssl_encryption_initial;
     ssl->quic.enc_level_latest_recvd = wolfssl_encryption_initial;
+    ssl->quic.early_data_enabled = 0;
 
     while ((qd = ssl->quic.input_head)) {
         ssl->quic.input_head = qd->next;
@@ -545,11 +546,11 @@ void wolfSSL_set_quic_early_data_enabled(WOLFSSL* ssl, int enabled)
     else if (ssl->options.handShakeState != NULL_STATE) {
         WOLFSSL_MSG("wolfSSL_set_quic_early_data_enabled: handshake started");
     }
-    else if (ssl->options.side == WOLFSSL_CLIENT_END) {
-        WOLFSSL_MSG("wolfSSL_set_quic_early_data_enabled: on client side");
-    }
     else {
-        wolfSSL_set_max_early_data(ssl, enabled ? UINT32_MAX : 0);
+        ssl->quic.early_data_enabled = enabled;
+        if (ssl->options.side != WOLFSSL_CLIENT_END) {
+            wolfSSL_set_max_early_data(ssl, enabled ? UINT32_MAX : 0);
+        }
     }
 }
 #endif /* WOLFSSL_EARLY_DATA */
@@ -576,19 +577,52 @@ int wolfSSL_quic_do_handshake(WOLFSSL* ssl)
          * and the client Finished arrives.
          * This confuses the QUIC state handling.
          */
+#ifdef WOLFSSL_EARLY_DATA
+        if (ssl->quic.early_data_enabled) {
+            byte tmpbuffer[256];
+            int len;
+
+            if (ssl->options.side == WOLFSSL_CLIENT_END) {
+                if (ssl->options.resuming) {
+                    ret = wolfSSL_write_early_data(ssl, tmpbuffer, 0, &len);
+                }
+            }
+            else if (/*disables code*/(1)) {
+                ret = wolfSSL_read_early_data(ssl, tmpbuffer,
+                                              sizeof(tmpbuffer), &len);
+                if (ret < 0 && ssl->error == ZERO_RETURN) {
+                    /* this is expected, since QUIC handles the actual early
+                     * data separately. */
+                    ret = WOLFSSL_SUCCESS;
+                }
+            }
+            if (ret < 0) {
+                goto cleanup;
+            }
+        }
+#endif /* WOLFSSL_EARLY_DATA */
+
         ret = wolfSSL_SSL_do_handshake(ssl);
-        if (ret != WOLFSSL_SUCCESS)
+        if (ret <= 0)
             goto cleanup;
     }
 
 cleanup:
+    if (ret <= 0
+        && ssl->options.handShakeState == HANDSHAKE_DONE
+        && (ssl->error == ZERO_RETURN || ssl->error == WANT_READ)) {
+        ret = WOLFSSL_SUCCESS;
+    }
+    if (ret == WOLFSSL_SUCCESS) {
+        ssl->error = WOLFSSL_ERROR_NONE;
+    }
     WOLFSSL_LEAVE("wolfSSL_quic_do_handshake", ret);
     return ret;
 }
 
 int wolfSSL_quic_read_write(WOLFSSL* ssl)
 {
-    int ret = WOLFSSL_SUCCESS, nret;
+    int ret = WOLFSSL_SUCCESS;
 
     WOLFSSL_ENTER("wolfSSL_quic_read_write");
 
@@ -604,16 +638,7 @@ int wolfSSL_quic_read_write(WOLFSSL* ssl)
             goto cleanup;
     }
 
-    while (ssl->quic.input_head != NULL
-           || ssl->buffers.inputBuffer.length > 0) {
-        if ((nret = ProcessReply(ssl)) < 0) {
-            ret = nret;
-            goto cleanup;
-        }
-    }
-    while (ssl->buffers.outputBuffer.length > 0) {
-        SendBuffered(ssl);
-    }
+    ret = wolfSSL_process_quic_post_handshake(ssl);
 
 cleanup:
     WOLFSSL_LEAVE("wolfSSL_quic_read_write", ret);
@@ -642,7 +667,7 @@ int wolfSSL_process_quic_post_handshake(WOLFSSL* ssl)
            || ssl->buffers.inputBuffer.length > 0) {
         if ((nret = ProcessReply(ssl)) < 0) {
             ret = nret;
-            goto cleanup;
+            break;
         }
     }
     while (ssl->buffers.outputBuffer.length > 0) {

+ 1 - 1
src/tls13.c

@@ -8085,7 +8085,7 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
 #endif /* WOLFSSL_DTLS13 && WOLFSSL_EARLY_DATA */
 #if defined(WOLFSSL_QUIC) && defined(WOLFSSL_EARLY_DATA)
     if (WOLFSSL_IS_QUIC(ssl) && ssl->earlyData > early_data_ext) {
-        /* QUIC has no EndOfearlydata messages. We stop processing EarlyData
+        /* QUIC has no EndOfEarlyData messages. We stop processing EarlyData
            as soon we receive the client's finished message */
         ssl->earlyData = done_early_data;
     }

+ 3 - 9
tests/quic.c

@@ -1007,12 +1007,7 @@ static void QuicConversation_do(QuicConversation *conv)
         if (!QuicConversation_step(conv)) {
             int c_err = wolfSSL_get_error(conv->client->ssl, 0);
             int s_err = wolfSSL_get_error(conv->server->ssl, 0);
-            if (c_err == 0
-                && (s_err == 0
-                    || (conv->sent_early_data && s_err == SSL_ERROR_WANT_READ))) {
-                /* Since QUIC does not use EndOfEarlyData messages, we may
-                 * encounter WANT_READ on the server side. QUIC protocol stacks
-                 * detect EOF here differently, so this should be fine. */
+            if (c_err == 0 && s_err == 0) {
                 break;  /* handshake done */
             }
             printf("Neither tclient nor server have anything to send, "
@@ -1245,12 +1240,11 @@ static int test_quic_early_data(int verbose) {
     AssertIntEQ(wolfSSL_set_session(tclient.ssl, session), WOLFSSL_SUCCESS);
     /* enable early data -*/
     wolfSSL_set_quic_early_data_enabled(tserver.ssl, 1);
-    /* client will send, but server will not receive, since
-     * QuicConversation_do() uses wolfSSL_accept() */
+    /* client will send, and server will receive implicitly */
     QuicConversation_init(&conv, &tclient, &tserver);
     QuicConversation_start(&conv, early_data, sizeof(early_data), &ed_written);
     QuicConversation_do(&conv);
-    AssertIntEQ(wolfSSL_get_early_data_status(tclient.ssl), WOLFSSL_EARLY_DATA_REJECTED);
+    AssertIntEQ(wolfSSL_get_early_data_status(tclient.ssl), WOLFSSL_EARLY_DATA_ACCEPTED);
 
     QuicTestContext_free(&tclient);
     QuicTestContext_free(&tserver);

+ 1 - 0
wolfssl/internal.h

@@ -4981,6 +4981,7 @@ struct WOLFSSL {
         WOLFSSL_ENCRYPTION_LEVEL enc_level_write;
         WOLFSSL_ENCRYPTION_LEVEL enc_level_write_next;
         int transport_version;
+        int early_data_enabled;
         const QuicTransportParam* transport_local;
         const QuicTransportParam* transport_peer;
         const QuicTransportParam* transport_peer_draft;