From ea04ffc99fe9da24afe202ca668578509306b0c5 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 10 Aug 2022 15:17:30 +0200 Subject: [PATCH] QUIC session resumption and early data handshake handling. In test with ngtcp2 example client using openssl, session resumption against a QUIC wolfssl server failed. The error was tracked down to wolfSSL believing EaryData needs to be handled and returning SUCCESS from wolfSSL_SSL_do_handshake() after the server Finished had been sent. However the handshake was not complete and ngtcp2 invoked the post_handshake processing for new data arriving from the client. This failed a check in post processing that the ssl->handShakeState actually was HANDSHAKE_DONE. The workaround in this PR repeats do_handshake until the ssl state acually says it is complete. This way, session resumption works. Either this alternative do_handshake() is merged for QUIC protocol hanlders. Or we need to fix the 'normal' do_handshake() to no return SUCCESS when early data is expected on a QUIC WOLFSSL. --- src/quic.c | 35 ++++++++++++++++++++++++++++++++++- src/tls13.c | 7 +++++++ wolfssl/quic.h | 3 +++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/quic.c b/src/quic.c index f32ce693c..4fafc22a9 100644 --- a/src/quic.c +++ b/src/quic.c @@ -554,6 +554,37 @@ void wolfSSL_set_quic_early_data_enabled(WOLFSSL* ssl, int enabled) } #endif /* WOLFSSL_EARLY_DATA */ +int wolfSSL_quic_do_handshake(WOLFSSL* ssl) +{ + int ret = WOLFSSL_SUCCESS; + + WOLFSSL_ENTER("wolfSSL_quic_do_handshake"); + + if (!wolfSSL_is_quic(ssl)) { + WOLFSSL_MSG("WOLFSSL_QUIC_DO_HANDSHAKE not a QUIC SSL"); + ret = WOLFSSL_FAILURE; + goto cleanup; + } + + while (ssl->options.handShakeState != HANDSHAKE_DONE) { + /* Peculiar: do_handshake() is successful, but the state + * indicates that we are not DONE. This seems to happen + * when resuming sessions and an EARLY_DATA indicator + * is presented by the client. + * Theory: wolfSSL expects the APP to read the early data + * and silently continues the handshake when the EndOfEarlyData + * and the client Finished arrives. + * This confuses the QUIC state handling. + */ + ret = wolfSSL_SSL_do_handshake(ssl); + if (ret != WOLFSSL_SUCCESS) + goto cleanup; + } + +cleanup: + WOLFSSL_LEAVE("wolfSSL_quic_do_handshake", ret); + return ret; +} int wolfSSL_quic_read_write(WOLFSSL* ssl) { @@ -568,7 +599,7 @@ int wolfSSL_quic_read_write(WOLFSSL* ssl) } if (ssl->options.handShakeState != HANDSHAKE_DONE) { - ret = wolfSSL_SSL_do_handshake(ssl); + ret = wolfSSL_quic_do_handshake(ssl); if (ret != WOLFSSL_SUCCESS) goto cleanup; } @@ -603,6 +634,8 @@ int wolfSSL_process_quic_post_handshake(WOLFSSL* ssl) if (ssl->options.handShakeState != HANDSHAKE_DONE) { WOLFSSL_MSG("WOLFSSL_QUIC_POST_HS handshake is not done yet"); + fprintf(stderr, "WOLFSSL_QUIC_POST_HS, handShakeState is %d\n", + ssl->options.handShakeState); ret = WOLFSSL_FAILURE; goto cleanup; } diff --git a/src/tls13.c b/src/tls13.c index 4cb4c3743..ea98ba57f 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -8063,6 +8063,13 @@ int DoTls13Finished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, ssl->earlyData = done_early_data; } #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 + as soon we receive the client's finished message */ + ssl->earlyData = done_early_data; + } +#endif /* WOLFSSL_QUIC && WOLFSSL_EARLY_DATA */ WOLFSSL_LEAVE("DoTls13Finished", 0); WOLFSSL_END(WC_FUNC_FINISHED_DO); diff --git a/wolfssl/quic.h b/wolfssl/quic.h index da24fd0ac..08b26ff4c 100644 --- a/wolfssl/quic.h +++ b/wolfssl/quic.h @@ -189,6 +189,9 @@ WOLFSSL_API int wolfSSL_provide_quic_data(WOLFSSL* ssl, WOLFSSL_ENCRYPTION_LEVEL level, const uint8_t* data, size_t len); +WOLFSSL_API +int wolfSSL_quic_do_handshake(WOLFSSL* ssl); + /** * Process any CRYPTO data added post-handshake. */