Merge pull request #7102 from julek-wolfssl/gh/7093

server: allow reading 0-RTT data after writing 0.5-RTT data
This commit is contained in:
Sean Parkinson
2024-01-05 07:20:53 +10:00
committed by GitHub
4 changed files with 137 additions and 85 deletions

View File

@ -23985,7 +23985,9 @@ int SendData(WOLFSSL* ssl, const void* data, int sz)
} }
#ifdef WOLFSSL_EARLY_DATA #ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData != no_early_data) { if (ssl->options.side == WOLFSSL_CLIENT_END &&
ssl->earlyData != no_early_data &&
ssl->earlyData != done_early_data) {
if (ssl->options.handShakeState == HANDSHAKE_DONE) { if (ssl->options.handShakeState == HANDSHAKE_DONE) {
WOLFSSL_MSG("handshake complete, trying to send early data"); WOLFSSL_MSG("handshake complete, trying to send early data");
ssl->error = BUILD_MSG_ERROR; ssl->error = BUILD_MSG_ERROR;
@ -24079,7 +24081,9 @@ int SendData(WOLFSSL* ssl, const void* data, int sz)
return ssl->error = BAD_STATE_E; return ssl->error = BAD_STATE_E;
#ifdef WOLFSSL_EARLY_DATA #ifdef WOLFSSL_EARLY_DATA
isEarlyData = ssl->earlyData != no_early_data; isEarlyData = ssl->options.side == WOLFSSL_CLIENT_END &&
ssl->earlyData != no_early_data &&
ssl->earlyData != done_early_data;
#endif #endif
if (isEarlyData) { if (isEarlyData) {
@ -24247,7 +24251,8 @@ int ReceiveData(WOLFSSL* ssl, byte* output, int sz, int peek)
} }
#ifdef WOLFSSL_EARLY_DATA #ifdef WOLFSSL_EARLY_DATA
if (ssl->earlyData != no_early_data) { if (ssl->options.side == WOLFSSL_SERVER_END &&
ssl->earlyData > early_data_ext && ssl->earlyData < done_early_data) {
} }
else else
#endif #endif

View File

@ -3240,20 +3240,6 @@ int wolfSSL_write(WOLFSSL* ssl, const void* data, int sz)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
} }
#endif #endif
#ifdef WOLFSSL_EARLY_DATA
if (IsAtLeastTLSv1_3(ssl->version) &&
ssl->options.side == WOLFSSL_SERVER_END &&
ssl->options.acceptState >= TLS13_ACCEPT_FINISHED_SENT) {
/* We can send data without waiting on peer finished msg */
WOLFSSL_MSG("server sending data before receiving client finished");
}
else if (ssl->earlyData != no_early_data &&
(ret = wolfSSL_negotiate(ssl)) < 0) {
ssl->error = ret;
return WOLFSSL_FATAL_ERROR;
}
ssl->earlyData = no_early_data;
#endif
#ifdef HAVE_WRITE_DUP #ifdef HAVE_WRITE_DUP
{ /* local variable scope */ { /* local variable scope */

View File

@ -10378,6 +10378,8 @@ static int SendTls13EndOfEarlyData(WOLFSSL* ssl)
if (!ssl->options.groupMessages) if (!ssl->options.groupMessages)
ret = SendBuffered(ssl); ret = SendBuffered(ssl);
ssl->earlyData = done_early_data;
WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret); WOLFSSL_LEAVE("SendTls13EndOfEarlyData", ret);
WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_SEND); WOLFSSL_END(WC_FUNC_END_OF_EARLY_DATA_SEND);

View File

@ -68693,102 +68693,161 @@ static int test_tls13_pq_groups(void)
return EXPECT_RESULT(); return EXPECT_RESULT();
} }
static int test_dtls13_early_data(void) static int test_tls13_early_data(void)
{ {
EXPECT_DECLS; EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) && \ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_EARLY_DATA) && defined(HAVE_SESSION_TICKET) defined(WOLFSSL_EARLY_DATA) && defined(HAVE_SESSION_TICKET)
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
int written = 0; int written = 0;
int read = 0; int read = 0;
size_t i;
int splitEarlyData;
char msg[] = "This is early data"; char msg[] = "This is early data";
char msg2[] = "This is client data"; char msg2[] = "This is client data";
char msg3[] = "This is server data"; char msg3[] = "This is server data";
char msg4[] = "This is server immediate data"; char msg4[] = "This is server immediate data";
char msgBuf[50]; char msgBuf[50];
struct {
method_provider client_meth;
method_provider server_meth;
const char* tls_version;
int isUdp;
} params[] = {
#ifdef WOLFSSL_TLS13
{ wolfTLSv1_3_client_method, wolfTLSv1_3_server_method,
"TLS 1.3", 0 },
#endif
#ifdef WOLFSSL_DTLS13
{ wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method,
"DTLS 1.3", 1 },
#endif
};
XMEMSET(&test_ctx, 0, sizeof(test_ctx)); for (i = 0; i < sizeof(params)/sizeof(*params) && !EXPECT_FAIL(); i++) {
for (splitEarlyData = 0; splitEarlyData < 2; splitEarlyData++) {
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
WOLFSSL_SESSION *sess = NULL;
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, XMEMSET(&test_ctx, 0, sizeof(test_ctx));
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
/* Get a ticket so that we can do 0-RTT on the next connection */ fprintf(stderr, "\tEarly data with %s\n", params[i].tls_version);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
wolfSSL_free(ssl_c); ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
ssl_c = NULL; &ssl_s, params[i].client_meth, params[i].server_meth), 0);
wolfSSL_free(ssl_s);
ssl_s = NULL; /* Get a ticket so that we can do 0-RTT on the next connection */
XMEMSET(&test_ctx, 0, sizeof(test_ctx)); ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, /* Make sure we read the ticket */
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0); ExpectIntEQ(wolfSSL_read(ssl_c, msgBuf, sizeof(msgBuf)), -1);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
params[i].client_meth, params[i].server_meth), 0);
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
#ifdef WOLFSSL_DTLS13
if (params[i].isUdp) {
#ifdef WOLFSSL_DTLS13_NO_HRR_ON_RESUME #ifdef WOLFSSL_DTLS13_NO_HRR_ON_RESUME
ExpectIntEQ(wolfSSL_dtls13_no_hrr_on_resume(ssl_s, 1), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_dtls13_no_hrr_on_resume(ssl_s, 1), WOLFSSL_SUCCESS);
#else #else
/* Let's test this but we generally don't recommend turning off the /* Let's test this but we generally don't recommend turning off the
* cookie exchange */ * cookie exchange */
ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS); ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS);
#endif
}
#endif #endif
/* Test 0-RTT data */ /* Test 0-RTT data */
ExpectIntEQ(wolfSSL_write_early_data(ssl_c, msg, sizeof(msg), ExpectIntEQ(wolfSSL_write_early_data(ssl_c, msg, sizeof(msg),
&written), sizeof(msg)); &written), sizeof(msg));
ExpectIntEQ(written, sizeof(msg)); ExpectIntEQ(written, sizeof(msg));
ExpectIntEQ(wolfSSL_read_early_data(ssl_s, msgBuf, sizeof(msgBuf), if (splitEarlyData) {
&read), sizeof(msg)); ExpectIntEQ(wolfSSL_write_early_data(ssl_c, msg, sizeof(msg),
ExpectIntEQ(read, sizeof(msg)); &written), sizeof(msg));
ExpectStrEQ(msg, msgBuf); ExpectIntEQ(written, sizeof(msg));
}
/* Test 0.5-RTT data */ /* Read first 0-RTT data (if split otherwise entire data) */
ExpectIntEQ(wolfSSL_write(ssl_s, msg4, sizeof(msg4)), sizeof(msg4)); ExpectIntEQ(wolfSSL_read_early_data(ssl_s, msgBuf, sizeof(msgBuf),
&read), sizeof(msg));
ExpectIntEQ(read, sizeof(msg));
ExpectStrEQ(msg, msgBuf);
ExpectIntEQ(wolfSSL_connect(ssl_c), -1); /* Test 0.5-RTT data */
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), APP_DATA_READY); ExpectIntEQ(wolfSSL_write(ssl_s, msg4, sizeof(msg4)), sizeof(msg4));
ExpectIntEQ(wolfSSL_read(ssl_c, msgBuf, sizeof(msgBuf)), sizeof(msg4)); if (splitEarlyData) {
ExpectStrEQ(msg4, msgBuf); /* Read second 0-RTT data */
ExpectIntEQ(wolfSSL_read_early_data(ssl_s, msgBuf, sizeof(msgBuf),
&read), sizeof(msg));
ExpectIntEQ(read, sizeof(msg));
ExpectStrEQ(msg, msgBuf);
}
/* Complete handshake */ if (params[i].isUdp) {
ExpectIntEQ(wolfSSL_connect(ssl_c), -1); ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), APP_DATA_READY);
/* Use wolfSSL_is_init_finished to check if handshake is complete. Normally
* a user would loop until it is true but here we control both sides so we
* just assert the expected value. wolfSSL_read_early_data does not provide
* handshake status to us with non-blocking IO and we can't use
* wolfSSL_accept as TLS layer may return ZERO_RETURN due to early data
* parsing logic. */
ExpectFalse(wolfSSL_is_init_finished(ssl_s));
ExpectIntEQ(wolfSSL_read_early_data(ssl_s, msgBuf, sizeof(msgBuf),
&read), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); /* Read server 0.5-RTT data */
ExpectIntEQ(wolfSSL_read(ssl_c, msgBuf, sizeof(msgBuf)), sizeof(msg4));
ExpectStrEQ(msg4, msgBuf);
ExpectTrue(wolfSSL_is_init_finished(ssl_s)); /* Complete handshake */
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
/* Use wolfSSL_is_init_finished to check if handshake is complete. Normally
* a user would loop until it is true but here we control both sides so we
* just assert the expected value. wolfSSL_read_early_data does not provide
* handshake status to us with non-blocking IO and we can't use
* wolfSSL_accept as TLS layer may return ZERO_RETURN due to early data
* parsing logic. */
ExpectFalse(wolfSSL_is_init_finished(ssl_s));
ExpectIntEQ(wolfSSL_read_early_data(ssl_s, msgBuf, sizeof(msgBuf),
&read), 0);
ExpectTrue(wolfSSL_is_init_finished(ssl_s));
ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
}
else {
ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
/* Test bi-directional write */ ExpectFalse(wolfSSL_is_init_finished(ssl_s));
ExpectIntEQ(wolfSSL_write(ssl_c, msg2, sizeof(msg2)), sizeof(msg2)); ExpectIntEQ(wolfSSL_read_early_data(ssl_s, msgBuf, sizeof(msgBuf),
ExpectIntEQ(wolfSSL_read(ssl_s, msgBuf, sizeof(msgBuf)), sizeof(msg2)); &read), 0);
ExpectStrEQ(msg2, msgBuf);
ExpectIntEQ(wolfSSL_write(ssl_s, msg3, sizeof(msg3)), sizeof(msg3));
ExpectIntEQ(wolfSSL_read(ssl_c, msgBuf, sizeof(msgBuf)), sizeof(msg3));
ExpectStrEQ(msg3, msgBuf);
ExpectTrue(wolfSSL_session_reused(ssl_c)); ExpectTrue(wolfSSL_is_init_finished(ssl_s));
ExpectTrue(wolfSSL_session_reused(ssl_s));
wolfSSL_SESSION_free(sess); /* Read server 0.5-RTT data */
wolfSSL_free(ssl_c); ExpectIntEQ(wolfSSL_read(ssl_c, msgBuf, sizeof(msgBuf)), sizeof(msg4));
wolfSSL_free(ssl_s); ExpectStrEQ(msg4, msgBuf);
wolfSSL_CTX_free(ctx_c); }
wolfSSL_CTX_free(ctx_s);
/* Test bi-directional write */
ExpectIntEQ(wolfSSL_write(ssl_c, msg2, sizeof(msg2)), sizeof(msg2));
ExpectIntEQ(wolfSSL_read(ssl_s, msgBuf, sizeof(msgBuf)), sizeof(msg2));
ExpectStrEQ(msg2, msgBuf);
ExpectIntEQ(wolfSSL_write(ssl_s, msg3, sizeof(msg3)), sizeof(msg3));
ExpectIntEQ(wolfSSL_read(ssl_c, msgBuf, sizeof(msgBuf)), sizeof(msg3));
ExpectStrEQ(msg3, msgBuf);
ExpectTrue(wolfSSL_session_reused(ssl_c));
ExpectTrue(wolfSSL_session_reused(ssl_s));
wolfSSL_SESSION_free(sess);
wolfSSL_free(ssl_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
}
}
#endif #endif
return EXPECT_RESULT(); return EXPECT_RESULT();
} }
@ -70188,7 +70247,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_dtls13_frag_ch_pq), TEST_DECL(test_dtls13_frag_ch_pq),
TEST_DECL(test_dtls_empty_keyshare_with_cookie), TEST_DECL(test_dtls_empty_keyshare_with_cookie),
TEST_DECL(test_tls13_pq_groups), TEST_DECL(test_tls13_pq_groups),
TEST_DECL(test_dtls13_early_data), TEST_DECL(test_tls13_early_data),
/* This test needs to stay at the end to clean up any caches allocated. */ /* This test needs to stay at the end to clean up any caches allocated. */
TEST_DECL(test_wolfSSL_Cleanup) TEST_DECL(test_wolfSSL_Cleanup)
}; };