QUIC fixes for handling of early data

- new internal field for keeping early data enabled status,
  as QUIC does not call SSL_write_early_data() itself.
- using read_/write_early_data() methods in QUIC handshake
  when early data is enabled. This triggers the internals
  that emit the proper early data indication handlings.
pull/5458/head
Stefan Eissing 2022-08-11 18:08:37 +02:00
parent dd2a6410d1
commit 53fd4b37f2
4 changed files with 47 additions and 29 deletions

View File

@ -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 buffer[256];
int len;
if (ssl->options.side == WOLFSSL_CLIENT_END) {
if (ssl->options.resuming) {
ret = wolfSSL_write_early_data(ssl, buffer, 0, &len);
}
}
else if (/*disables code*/(1)) {
ret = wolfSSL_read_early_data(ssl, buffer,
sizeof(buffer), &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);
@ -634,8 +659,6 @@ 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;
}
@ -644,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) {

View File

@ -8065,7 +8065,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;
}

View File

@ -999,12 +999,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, "
@ -1237,12 +1232,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);

View File

@ -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;