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
1 change: 1 addition & 0 deletions src/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5660,6 +5660,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
ssl->options.isClosed = 0;
ssl->options.connReset = 0;
ssl->options.sentNotify = 0;
ssl->options.sentUserCanceled = 0;
ssl->options.closeNotify = 0;
ssl->options.sendVerify = 0;
ssl->options.serverState = NULL_STATE;
Expand Down
16 changes: 15 additions & 1 deletion src/ssl_api_rw.c
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,10 @@ int wolfSSL_SendUserCanceled(WOLFSSL* ssl)

if (ssl != NULL) {
ssl->error = SendAlert(ssl, alert_warning, user_canceled);
if ((ssl->error == 0) ||
(ssl->error == WC_NO_ERR_TRACE(WANT_WRITE))) {
ssl->options.sentUserCanceled = 1;
}
if (ssl->error < 0) {
WOLFSSL_ERROR(ssl->error);
}
Expand Down Expand Up @@ -1030,10 +1034,20 @@ int wolfSSL_shutdown(WOLFSSL* ssl)
if (ssl == NULL) {
ret = WOLFSSL_FATAL_ERROR;
}
else if (ssl->options.quietShutdown) {
else if (ssl->options.quietShutdown && (!ssl->options.sentUserCanceled)) {
WOLFSSL_MSG("quiet shutdown, no close notify sent");
ret = WOLFSSL_SUCCESS;
}
else if (ssl->options.quietShutdown) {
/* A "user_canceled" alert has gone out so we need a "close_notify" to
* follow it per RFC 9846 Section 6.1. */
Comment thread
holtrop-wolfssl marked this conversation as resolved.
if (!wolfssl_shutdown_flush_alert(ssl, &ret)) {
(void)wolfssl_shutdown_send_close_notify(ssl, &ret);
}
if (ret == WC_NO_ERR_TRACE(WOLFSSL_SHUTDOWN_NOT_DONE)) {
ret = WOLFSSL_SUCCESS;
}
}
else {
int done;

Expand Down
72 changes: 72 additions & 0 deletions tests/api/test_ssl_rw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,78 @@ int test_wolfSSL_SendUserCanceled_paths(void)
return EXPECT_RESULT();
}

/* Test that quiet shutdown does not suppress the close_notify that the
* user_canceled alert obliges wolfSSL to send.
*
* RFC 9846 Section 6.1 has a "close_notify" following "user_canceled" and has
Comment thread
holtrop-wolfssl marked this conversation as resolved.
* the peer keep reading until it arrives. Quiet shutdown may drop the
* close_notify that stands alone - that is what the option is for - but not
* the one the peer has been told to wait for.
*
* @return TEST_SUCCESS on success.
*/
int test_wolfSSL_SendUserCanceled_quiet_shutdown(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_TLS) && \
!defined(WOLFSSL_NO_TLS12) && (defined(OPENSSL_EXTRA) || \
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_EXTRA) || \
defined(WOLFSSL_WPAS_SMALL))
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 reply[16];

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(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

wolfSSL_set_quiet_shutdown(ssl_c, 1);
/* Both alerts go out. Waiting for the peer's reply is what quiet shutdown
* skips, so the shutdown is done as far as this side is concerned. */
ExpectIntEQ(wolfSSL_SendUserCanceled(ssl_c), WOLFSSL_SUCCESS);

/* The server reads the user_canceled and then the close_notify, which is
* what it reports. Without the close_notify it would still be waiting. */
ExpectIntEQ(wolfSSL_read(ssl_s, reply, (int)sizeof(reply)), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, 0), WOLFSSL_ERROR_ZERO_RETURN);
ExpectIntEQ(wolfSSL_get_shutdown(ssl_s), WOLFSSL_RECEIVED_SHUTDOWN);

wolfSSL_free(ssl_c);
ssl_c = NULL;
wolfSSL_free(ssl_s);
ssl_s = NULL;
wolfSSL_CTX_free(ctx_c);
ctx_c = NULL;
wolfSSL_CTX_free(ctx_s);
ctx_s = NULL;

/* A quiet shutdown with no user_canceled behind it still sends nothing:
* that is the whole point of the option. */
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(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);

wolfSSL_set_quiet_shutdown(ssl_c, 1);
ExpectIntEQ(wolfSSL_shutdown(ssl_c), WOLFSSL_SUCCESS);

/* Nothing arrived, so the server is still waiting for a record. */
ExpectIntLT(wolfSSL_read(ssl_s, reply, (int)sizeof(reply)), 0);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
Comment thread
holtrop-wolfssl marked this conversation as resolved.
ExpectIntEQ(wolfSSL_get_shutdown(ssl_s), 0);

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

/* Test that an error the read side recorded is the one the write reports.
*
* With a write duplicate in use the read side hands errors over through
Expand Down
3 changes: 3 additions & 0 deletions tests/api/test_ssl_rw.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ int test_wolfSSL_shutdown_repeat_after_done(void);
int test_wolfSSL_shutdown_flush_no_notify(void);
int test_wolfSSL_shutdown_quic_alert_refused(void);
int test_wolfSSL_SendUserCanceled_paths(void);
int test_wolfSSL_SendUserCanceled_quiet_shutdown(void);
int test_wolfSSL_write_dup_err(void);

#define TEST_SSL_RW_DECLS \
Expand All @@ -56,6 +57,8 @@ int test_wolfSSL_write_dup_err(void);
TEST_DECL_GROUP("ssl_rw", test_wolfSSL_shutdown_flush_no_notify), \
TEST_DECL_GROUP("ssl_rw", test_wolfSSL_shutdown_quic_alert_refused), \
TEST_DECL_GROUP("ssl_rw", test_wolfSSL_SendUserCanceled_paths), \
TEST_DECL_GROUP("ssl_rw", \
test_wolfSSL_SendUserCanceled_quiet_shutdown), \
TEST_DECL_GROUP("ssl_rw", test_wolfSSL_write_dup_err)

#endif /* TESTS_API_SSL_RW_H */
2 changes: 2 additions & 0 deletions wolfssl/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -5441,6 +5441,8 @@ struct Options {
word16 isClosed:1; /* if we consider conn closed */
word16 closeNotify:1; /* we've received a close notify */
word16 sentNotify:1; /* we've sent a close notify */
word16 sentUserCanceled:1; /* we've sent a user_canceled and
* owe the peer a close notify */
Comment thread
holtrop-wolfssl marked this conversation as resolved.
word16 usingCompression:1; /* are we using compression */
word16 haveRSA:1; /* RSA available */
word16 haveECC:1; /* ECC available */
Expand Down
Loading