Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 1 addition & 30 deletions src/ssl_api_rw.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,6 @@ static int wolfssl_write_dup_take_tls13_work(WOLFSSL* ssl)
*
* @param [in, out] ssl SSL/TLS object of the write side.
* @return 0 on success.
* @return BAD_MUTEX_E when the write duplicate could not be locked. Returned
* as-is by the caller, so ssl->error is not set for it.
* @return WOLFSSL_FATAL_ERROR on error. Call wolfSSL_get_error() for the
* reason.
*/
Expand All @@ -161,6 +159,7 @@ static int wolfssl_write_dup_do_tls13_work(WOLFSSL* ssl)
if (ssl->postHandshakeAuthPending) {
/* reset handshake states */
ssl->postHandshakeAuthPending = 0;
ssl->postHandshakeAuthPublish = 1;
ssl->options.clientState = CLIENT_HELLO_COMPLETE;
ssl->options.connectState = FIRST_REPLY_DONE;
ssl->options.handShakeState = CLIENT_HELLO_COMPLETE;
Expand All @@ -173,34 +172,6 @@ static int wolfssl_write_dup_do_tls13_work(WOLFSSL* ssl)
}
ret = WOLFSSL_FATAL_ERROR;
}
/* PHA response fully sent: publish the write side's updated
* transcript to the read side for the next PHA round. */
else if ((ssl->hsHashes != NULL) && (ssl->dupWrite != NULL)) {
if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) {
ret = BAD_MUTEX_E;
}
else {
int syncRet = InitHandshakeHashesAndCopy(ssl,
ssl->hsHashes,
&ssl->dupWrite->postHandshakeSyncedHashState);
if (syncRet != 0) {
/* On failure the copy may have left a partially
* initialized transcript. The read side only checks
* for non-NULL before consuming it, so drop it here to
* avoid hashing onto a corrupt transcript, and surface
* the error to the caller. */
Free_HS_Hashes(
ssl->dupWrite->postHandshakeSyncedHashState,
ssl->heap);
ssl->dupWrite->postHandshakeSyncedHashState = NULL;
}
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
if (syncRet != 0) {
ssl->error = syncRet;
ret = WOLFSSL_FATAL_ERROR;
}
}
}
}
#endif /* WOLFSSL_POST_HANDSHAKE_AUTH */

Expand Down
37 changes: 37 additions & 0 deletions src/tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -16701,6 +16701,32 @@ int DoTls13HandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx,

#ifndef NO_WOLFSSL_CLIENT

#if defined(HAVE_WRITE_DUP) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
static int Tls13WriteDupPublishPhaHashes(WOLFSSL* ssl)
{
int ret = 0;

if ((ssl->hsHashes != NULL) && (ssl->dupWrite != NULL)) {
if (wc_LockMutex(&ssl->dupWrite->dupMutex) != 0) {
ret = BAD_MUTEX_E;
}
else {
ret = InitHandshakeHashesAndCopy(ssl, ssl->hsHashes,
&ssl->dupWrite->postHandshakeSyncedHashState);
if (ret != 0) {
/* Drop a partial copy so the read side never hashes onto it */
Free_HS_Hashes(ssl->dupWrite->postHandshakeSyncedHashState,
ssl->heap);
ssl->dupWrite->postHandshakeSyncedHashState = NULL;
}
wc_UnLockMutex(&ssl->dupWrite->dupMutex);
}
}

return ret;
}
#endif /* HAVE_WRITE_DUP && WOLFSSL_POST_HANDSHAKE_AUTH */

/* The client connecting to the server.
* The protocol version is expecting to be TLS v1.3.
* If the server downgrades, and older versions of the protocol are compiled
Expand Down Expand Up @@ -17140,6 +17166,17 @@ int wolfSSL_connect_TLSv13(WOLFSSL* ssl)
FreeAsyncCtx(ssl, 1);
#endif

#if defined(HAVE_WRITE_DUP) && defined(WOLFSSL_POST_HANDSHAKE_AUTH)
if (ssl->postHandshakeAuthPublish) {
ssl->postHandshakeAuthPublish = 0;
ssl->error = Tls13WriteDupPublishPhaHashes(ssl);
if (ssl->error != 0) {
WOLFSSL_ERROR(ssl->error);
return WOLFSSL_FATAL_ERROR;
}
}
#endif

ssl->error = 0; /* clear the error */

WOLFSSL_LEAVE("wolfSSL_connect_TLSv13", WOLFSSL_SUCCESS);
Expand Down
126 changes: 126 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -42804,6 +42804,10 @@ static int test_write_dup(void)
ExpectIntEQ(wolfSSL_get_chain_count(chain), 1);
for (k = 0; k < 10; k++)
EXCHANGE_DATA;
/* Second round hashes onto the first round's transcript. */
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
}
#endif

Expand Down Expand Up @@ -42942,6 +42946,10 @@ static int test_write_dup_want_write(void)
ExpectIntEQ(wolfSSL_get_chain_count(chain), 1);
for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
/* Second round after a response that blocked once. */
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
for (k = 0; k < 10 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
}
#endif /* WOLFSSL_POST_HANDSHAKE_AUTH && SESSION_CERTS */

Expand Down Expand Up @@ -43069,6 +43077,123 @@ static int test_write_dup_want_write_simul(void)
return EXPECT_RESULT();
}

/* wolfSSL_negotiate() on the write side outside a PHA response leaves the
* transcript copy for the read side alone. */
static int test_write_dup_negotiate_pha(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP) && \
defined(WOLFSSL_POST_HANDSHAKE_AUTH) && defined(WOLFSSL_TLS13) && \
defined(SESSION_CERTS)
size_t i, k;
char hiWorld[] = "dup message";
char readData[sizeof(hiWorld) + 5];
struct {
method_provider client_meth;
method_provider server_meth;
const char* version_name;
} methods[] = {
{wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLS 1.3"},
#ifdef WOLFSSL_DTLS13
{wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLS 1.3"},
#endif
};

#define EXCHANGE_DATA do { \
ExpectIntEQ(wolfSSL_write(ssl_s, hiWorld, sizeof(hiWorld)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_read(ssl_c, readData, sizeof(readData)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_write(ssl_c2, hiWorld, sizeof(hiWorld)), \
sizeof(hiWorld)); \
ExpectIntEQ(wolfSSL_read(ssl_s, readData, sizeof(readData)), \
sizeof(hiWorld)); \
} while (0)

for (i = 0; i < XELEM_CNT(methods) && !EXPECT_FAIL(); i++) {
struct test_memio_ctx test_ctx;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
HS_Hashes* synced = NULL;
WOLFSSL *ssl_c2 = NULL;
WOLFSSL_X509_CHAIN* chain = NULL;

if (i == 0)
printf("\n");
printf("Testing write_dup negotiate and PHA %s... ",
methods[i].version_name);

XMEMSET(&test_ctx, 0, sizeof(test_ctx));

ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
methods[i].client_meth, methods[i].server_meth), 0);
ExpectIntEQ(wolfSSL_CTX_use_certificate_file(ctx_c, cliCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx_c, cliKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_allow_post_handshake_auth(ssl_c), 0);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, caCertFile,
NULL), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

ExpectNotNull(ssl_c2 = wolfSSL_write_dup(ssl_c));
EXCHANGE_DATA;

/* Before any PHA round there is nothing to copy. */
ExpectIntEQ(wolfSSL_negotiate(ssl_c2), WOLFSSL_SUCCESS);
if (EXPECT_SUCCESS()) {
ExpectNull(ssl_c2->dupWrite->postHandshakeSyncedHashState);
}

ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
for (k = 0; k < 3 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;
ExpectNotNull(chain = wolfSSL_get_peer_chain(ssl_s));
ExpectIntEQ(wolfSSL_get_chain_count(chain), 1);

/* After a round, negotiate does not copy the transcript again. Take
* the copy off so a new one shows up whatever address it gets. */
if (EXPECT_SUCCESS()) {
synced = ssl_c2->dupWrite->postHandshakeSyncedHashState;
ssl_c2->dupWrite->postHandshakeSyncedHashState = NULL;
}
ExpectNotNull(synced);
ExpectIntEQ(wolfSSL_negotiate(ssl_c2), WOLFSSL_SUCCESS);
if (ssl_c2 != NULL) {
ExpectNull(ssl_c2->dupWrite->postHandshakeSyncedHashState);
if (ssl_c2->dupWrite->postHandshakeSyncedHashState == NULL) {
ssl_c2->dupWrite->postHandshakeSyncedHashState = synced;
}
else {
/* wolfSSL_free() releases this field too */
ssl_c2->dupWrite->postHandshakeHashState = synced;
}
}

ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
for (k = 0; k < 3 && !EXPECT_FAIL(); k++)
EXCHANGE_DATA;

if (EXPECT_SUCCESS())
printf("ok\n");
else
printf("failed\n");

wolfSSL_free(ssl_c);
wolfSSL_free(ssl_c2);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_c);
wolfSSL_CTX_free(ctx_s);
}
#undef EXCHANGE_DATA
#endif
return EXPECT_RESULT();
}

#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(HAVE_WRITE_DUP) && \
defined(HAVE_CHACHA) && defined(HAVE_POLY1305) && !defined(NO_SHA256) && \
(defined(HAVE_ECC) || defined(HAVE_CURVE25519) || \
Expand Down Expand Up @@ -47369,6 +47494,7 @@ TEST_CASE testCases[] = {
TEST_DECL(test_write_dup),
TEST_DECL(test_write_dup_want_write),
TEST_DECL(test_write_dup_want_write_simul),
TEST_DECL(test_write_dup_negotiate_pha),
TEST_DECL(test_write_dup_oom),
TEST_DECL(test_wc_SrpComputeKey_oom),
TEST_DECL(test_read_write_hs),
Expand Down
1 change: 1 addition & 0 deletions wolfssl/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -7605,6 +7605,7 @@ struct WOLFSSL {
#ifdef WOLFSSL_TLS13
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
WC_BITFIELD postHandshakeAuthPending:1;
WC_BITFIELD postHandshakeAuthPublish:1;
#endif
#endif
#endif
Expand Down
Loading