1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00

Do not answer the peer after our close_notify

The previous commit stopped wolfSSL_write() from building handshake or
KeyUpdate records after a fatal alert or our close_notify. Records the
peer provokes still went out after that point:

- wolfSSL_negotiate() in ReceiveData(), including the secure
  renegotiation one in its loop. After wolfSSL_SendUserCanceled()
  cancelled a handshake, a wolfSSL_read() still finished the handshake
  and sent the Finished.
- DoTls13KeyUpdate() answering a peer's update_requested. This is
  reached from wolfSSL_read() and from the wolfSSL_shutdown() loop
  waiting for the peer's close_notify.
- A post-handshake CertificateRequest, answered with Certificate,
  CertificateVerify and Finished from inside ProcessReply().
- A TLS 1.2 HelloRequest, which started a renegotiation from
  ReceiveData().
- The write side of a write duplicate sending a PHA response or
  KeyUpdate delegated by the read side.

Skip all of them once sentNotify or fatalAlert is set. A peer KeyUpdate
still moves our receive keys forward, so a half-closed connection keeps
reading.

Extend test_tls13_no_handshake_after_user_canceled with a read, and add
test_tls13_no_key_update_response_after_close_notify (read and
shutdown), test_tls13_no_pha_response_after_close_notify,
test_tls13_write_dup_no_response_after_close_notify and
test_tls12_no_renegotiation_after_close_notify (HelloRequest and
ClientHello).
This commit is contained in:
Tobias Frauenschläger
2026-10-21 11:35:55 +02:00
committed by Paul Adelsbach
parent 24c44ac717
commit 2fd8dc2375
5 changed files with 257 additions and 2 deletions

View File

@@ -20608,6 +20608,12 @@ static int DoHelloRequest(WOLFSSL* ssl, word32 size)
WOLFSSL_ERROR_VERBOSE(FATAL_ERROR);
return FATAL_ERROR;
}
else if (ssl->options.sentNotify || ssl->options.fatalAlert) {
WOLFSSL_MSG("Ignoring HelloRequest after close_notify");
WOLFSSL_LEAVE("DoHelloRequest", 0);
WOLFSSL_END(WC_FUNC_HELLO_REQUEST_DO);
return 0;
}
#ifdef HAVE_SECURE_RENEGOTIATION
else if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled &&
!ssl->secure_renegotiation->advertiseOnly) {
@@ -30850,7 +30856,9 @@ int ReceiveData(WOLFSSL* ssl, byte* output, size_t sz, int peek)
else
#endif
{
if (ssl_in_handshake(ssl, 0)) {
/* No handshake records after our close_notify or a fatal alert */
if (!ssl->options.sentNotify && !ssl->options.fatalAlert &&
ssl_in_handshake(ssl, 0)) {
int err;
WOLFSSL_MSG("Handshake not complete, trying to finish");
if ( (err = wolfSSL_negotiate(ssl)) != WOLFSSL_SUCCESS) {
@@ -30918,7 +30926,8 @@ startScr:
}
if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled &&
ssl->options.handShakeState != HANDSHAKE_DONE
&& ssl->buffers.clearOutputBuffer.length == 0) {
&& ssl->buffers.clearOutputBuffer.length == 0
&& !ssl->options.sentNotify && !ssl->options.fatalAlert) {
/* ProcessReply processed a handshake packet and not any APP DATA
* so let's move the handshake along */
int err;

View File

@@ -142,6 +142,17 @@ static int wolfssl_write_dup_do_tls13_work(WOLFSSL* ssl)
{
int ret = 0;
if (ssl->options.sentNotify || ssl->options.fatalAlert) {
WOLFSSL_MSG("Dropping delegated responses after close_notify");
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
ssl->postHandshakeAuthPending = 0;
#endif
ssl->keys.keyUpdateRespond = 0;
#ifdef WOLFSSL_DTLS13
ssl->dtls13DoKeyUpdate = 0;
#endif
}
if (IsAtLeastTLSv1_3(ssl->version)) {
#ifdef WOLFSSL_POST_HANDSHAKE_AUTH
/* Read side received a CertificateRequest but couldn't write;

View File

@@ -14445,6 +14445,11 @@ static int DoTls13KeyUpdate(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
#endif /* WOLFSSL_DTLS13 */
if (ssl->keys.keyUpdateRespond) {
if (ssl->options.sentNotify || ssl->options.fatalAlert) {
WOLFSSL_MSG("Not answering KeyUpdate after close_notify");
ssl->keys.keyUpdateRespond = 0;
return 0;
}
#ifdef WOLFSSL_DTLS13
/* we already sent a keyUpdate (either in response to a previous
@@ -16396,6 +16401,11 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (ssl->options.side == WOLFSSL_CLIENT_END) {
if (type == certificate_request &&
ssl->options.handShakeState == HANDSHAKE_DONE) {
if (ssl->options.sentNotify || ssl->options.fatalAlert) {
WOLFSSL_MSG("Ignoring CertificateRequest after "
"close_notify");
}
else
#if defined(HAVE_WRITE_DUP)
/* Read side cannot write; delegate the cert response to the
* write side by saving auth state in the shared WriteDup. */

View File

@@ -13623,6 +13623,14 @@ int test_tls13_no_handshake_after_user_canceled(void)
if (ssl_c != NULL)
ExpectIntEQ(ssl_c->options.handShakeDone, 0);
ExpectIntEQ(wolfSSL_read(ssl_c, msg, (int)sizeof(msg)),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(test_ctx.s_len, s_len_before);
if (ssl_c != NULL)
ExpectIntEQ(ssl_c->options.handShakeDone, 0);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
@@ -13675,6 +13683,215 @@ int test_tls13_no_key_update_after_close_notify(void)
return EXPECT_RESULT();
}
int test_tls13_no_key_update_response_after_close_notify(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
char readBuf[32];
char msg[] = "after update";
int c_len_before;
int useShutdown;
for (useShutdown = 0; useShutdown < 2 && EXPECT_SUCCESS(); useShutdown++) {
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE);
ExpectIntEQ(wolfSSL_update_keys(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_write(ssl_c, msg, (int)sizeof(msg)),
(int)sizeof(msg));
c_len_before = test_ctx.c_len;
if (useShutdown) {
ExpectIntEQ(wolfSSL_shutdown(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE);
}
else {
ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, (int)sizeof(readBuf)),
(int)sizeof(msg));
ExpectBufEQ(readBuf, msg, sizeof(msg));
}
ExpectIntEQ(test_ctx.c_len, c_len_before);
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_CTX_free(ctx_c);
ctx_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
wolfSSL_CTX_free(ctx_s);
ctx_s = NULL;
}
#endif
return EXPECT_RESULT();
}
int test_tls13_no_pha_response_after_close_notify(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_RSA) && !defined(NO_CERTS)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
char readBuf[32];
char msg[] = "after request";
int s_len_before;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, NULL),
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(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SHUTDOWN_NOT_DONE);
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_write(ssl_s, msg, (int)sizeof(msg)), (int)sizeof(msg));
s_len_before = test_ctx.s_len;
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, (int)sizeof(readBuf)),
(int)sizeof(msg));
ExpectBufEQ(readBuf, msg, sizeof(msg));
ExpectIntEQ(test_ctx.s_len, s_len_before);
if (ssl_c != NULL)
ExpectIntEQ(ssl_c->options.handShakeState, HANDSHAKE_DONE);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls13_write_dup_no_response_after_close_notify(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(HAVE_WRITE_DUP) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
!defined(NO_RSA) && !defined(NO_CERTS)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
WOLFSSL *ssl_w = NULL;
struct test_memio_ctx test_ctx;
char readBuf[32];
char msg[] = "dup message";
int s_len_before;
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
ExpectIntEQ(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile, NULL),
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(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
ExpectNotNull(ssl_w = wolfSSL_write_dup(ssl_c));
/* Drain the session tickets so the write side's shutdown reads nothing */
ExpectIntEQ(wolfSSL_write(ssl_s, msg, (int)sizeof(msg)), (int)sizeof(msg));
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, (int)sizeof(readBuf)),
(int)sizeof(msg));
ExpectIntEQ(wolfSSL_shutdown(ssl_w), WOLFSSL_SHUTDOWN_NOT_DONE);
ExpectIntEQ(wolfSSL_update_keys(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_write(ssl_s, msg, (int)sizeof(msg)), (int)sizeof(msg));
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, (int)sizeof(readBuf)),
(int)sizeof(msg));
ExpectBufEQ(readBuf, msg, sizeof(msg));
s_len_before = test_ctx.s_len;
ExpectIntEQ(wolfSSL_write(ssl_w, msg, (int)sizeof(msg)),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
ExpectIntEQ(wolfSSL_get_error(ssl_w, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WC_NO_ERR_TRACE(SSL_SHUTDOWN_ALREADY_DONE_E));
ExpectIntEQ(test_ctx.s_len, s_len_before);
wolfSSL_free(ssl_w);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_c);
wolfSSL_free(ssl_s);
wolfSSL_CTX_free(ctx_s);
#endif
return EXPECT_RESULT();
}
int test_tls12_no_renegotiation_after_close_notify(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(HAVE_SECURE_RENEGOTIATION) && !defined(WOLFSSL_NO_TLS12) && \
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
WOLFSSL_CTX *ctx_c = NULL;
WOLFSSL_CTX *ctx_s = NULL;
WOLFSSL *ssl_c = NULL;
WOLFSSL *ssl_s = NULL;
WOLFSSL *closer;
WOLFSSL *peer;
struct test_memio_ctx test_ctx;
char readBuf[32];
int *closerOutLen;
int lenBefore;
int serverCloses;
for (serverCloses = 0; serverCloses < 2 && EXPECT_SUCCESS();
serverCloses++) {
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
ExpectIntEQ(wolfSSL_UseSecureRenegotiation(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_UseSecureRenegotiation(ssl_s), WOLFSSL_SUCCESS);
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
closer = serverCloses ? ssl_s : ssl_c;
peer = serverCloses ? ssl_c : ssl_s;
closerOutLen = serverCloses ? &test_ctx.c_len : &test_ctx.s_len;
/* HelloRequest to a closed client, or ClientHello to a closed server */
ExpectIntEQ(wolfSSL_shutdown(closer), WOLFSSL_SHUTDOWN_NOT_DONE);
ExpectIntEQ(wolfSSL_Rehandshake(peer),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
lenBefore = *closerOutLen;
ExpectIntEQ(wolfSSL_read(closer, readBuf, (int)sizeof(readBuf)),
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
ExpectIntEQ(wolfSSL_get_error(closer,
WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(*closerOutLen, lenBefore);
wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_CTX_free(ctx_c);
ctx_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
wolfSSL_CTX_free(ctx_s);
ctx_s = NULL;
}
#endif
return EXPECT_RESULT();
}
/* RFC 9846 Section 4.7.3, write-duplicate path. The read side of a write dup
* cannot send, so a peer KeyUpdate(update_requested) is delegated to the write
* side via dupWrite->keyUpdateRespond and sent from

View File

@@ -163,6 +163,10 @@ int test_tls13_no_write_after_close_notify(void);
int test_tls13_shutdown_after_refused_write(void);
int test_tls13_no_handshake_after_user_canceled(void);
int test_tls13_no_key_update_after_close_notify(void);
int test_tls13_no_key_update_response_after_close_notify(void);
int test_tls13_no_pha_response_after_close_notify(void);
int test_tls13_write_dup_no_response_after_close_notify(void);
int test_tls12_no_renegotiation_after_close_notify(void);
int test_tls13_pqc_hybrid_async_server(void);
int test_tls13_pha_status_request(void);
int test_tls13_x25519_keyshare_masks_reserved_bit(void);
@@ -334,6 +338,10 @@ int test_tls13_cks_hrr_reparse(void);
TEST_DECL_GROUP("tls13", test_tls13_shutdown_after_refused_write), \
TEST_DECL_GROUP("tls13", test_tls13_no_handshake_after_user_canceled), \
TEST_DECL_GROUP("tls13", test_tls13_no_key_update_after_close_notify), \
TEST_DECL_GROUP("tls13", test_tls13_no_key_update_response_after_close_notify), \
TEST_DECL_GROUP("tls13", test_tls13_no_pha_response_after_close_notify), \
TEST_DECL_GROUP("tls13", test_tls13_write_dup_no_response_after_close_notify), \
TEST_DECL_GROUP("tls13", test_tls12_no_renegotiation_after_close_notify), \
TEST_DECL_GROUP("tls13", test_tls13_pqc_hybrid_async_server), \
TEST_DECL_GROUP("tls13", test_tls13_x25519_keyshare_masks_reserved_bit), \
TEST_DECL_GROUP("tls13", test_tls13_is_init_finished_want_write), \