diff --git a/src/internal.c b/src/internal.c index a60d8bde7c..3620954ff1 100644 --- a/src/internal.c +++ b/src/internal.c @@ -24894,6 +24894,11 @@ static int SendAlert_ex(WOLFSSL* ssl, int severity, int type) #endif /* WOLFSSL_DTLS13 */ { AddRecordHeader(output, ALERT_SIZE, alert, ssl, CUR_ORDER); +#ifdef WOLFSSL_DTLS + /* AddRecordHeader doesn't increment the seq number */ + if (ssl->options.dtls) + DtlsSEQIncrement(ssl, CUR_ORDER); +#endif } output += RECORD_HEADER_SZ; diff --git a/src/ssl.c b/src/ssl.c index 5fd3364b90..f842d89056 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -3973,6 +3973,25 @@ int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags) } #endif +int wolfSSL_SendUserCanceled(WOLFSSL* ssl) +{ + int ret = WOLFSSL_FAILURE; + WOLFSSL_ENTER("wolfSSL_recv"); + + if (ssl != NULL) { + ssl->error = SendAlert(ssl, alert_warning, user_canceled); + if (ssl->error < 0) { + WOLFSSL_ERROR(ssl->error); + } + else { + ret = wolfSSL_shutdown(ssl); + } + } + + WOLFSSL_LEAVE("wolfSSL_SendUserCanceled", ret); + + return ret; +} /* WOLFSSL_SUCCESS on ok */ WOLFSSL_ABI diff --git a/tests/api.c b/tests/api.c index a9de815065..1025116302 100644 --- a/tests/api.c +++ b/tests/api.c @@ -72660,6 +72660,77 @@ static int test_tls_cert_store_unchanged(void) return EXPECT_RESULT(); } +static int test_wolfSSL_SendUserCanceled(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) + size_t i; + struct { + method_provider client_meth; + method_provider server_meth; + const char* tls_version; + } params[] = { +#if defined(WOLFSSL_TLS13) +/* With WOLFSSL_TLS13_MIDDLEBOX_COMPAT a short ID will result in an error */ + { wolfTLSv1_3_client_method, wolfTLSv1_3_server_method, "TLSv1_3" }, +#ifdef WOLFSSL_DTLS13 + { wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method, "DTLSv1_3" }, +#endif +#endif +#ifndef WOLFSSL_NO_TLS12 + { wolfTLSv1_2_client_method, wolfTLSv1_2_server_method, "TLSv1_2" }, +#ifdef WOLFSSL_DTLS + { wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method, "DTLSv1_2" }, +#endif +#endif +#if !defined(NO_OLD_TLS) + { wolfTLSv1_1_client_method, wolfTLSv1_1_server_method, "TLSv1_1" }, +#ifdef WOLFSSL_DTLS + { wolfDTLSv1_client_method, wolfDTLSv1_server_method, "DTLSv1_0" }, +#endif +#endif + }; + + for (i = 0; i < sizeof(params)/sizeof(*params) && !EXPECT_FAIL(); i++) { + WOLFSSL_CTX *ctx_c = NULL; + WOLFSSL_CTX *ctx_s = NULL; + WOLFSSL *ssl_c = NULL; + WOLFSSL *ssl_s = NULL; + struct test_memio_ctx test_ctx; + WOLFSSL_ALERT_HISTORY h; + + printf("Testing %s\n", params[i].tls_version); + + XMEMSET(&h, 0, sizeof(h)); + 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); + + /* CH1 */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + ExpectIntEQ(wolfSSL_SendUserCanceled(ssl_s), WOLFSSL_SHUTDOWN_NOT_DONE); + + /* Alert closed connection */ + ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_ZERO_RETURN); + + /* Last alert will be close notify because user_canceled should be + * followed by a close_notify */ + ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS); + ExpectIntEQ(h.last_rx.code, close_notify); + ExpectIntEQ(h.last_rx.level, alert_warning); + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + } +#endif + return EXPECT_RESULT(); +} + /*----------------------------------------------------------------------------* | Main *----------------------------------------------------------------------------*/ @@ -73989,6 +74060,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_read_write_hs), TEST_DECL(test_get_signature_nid), TEST_DECL(test_tls_cert_store_unchanged), + TEST_DECL(test_wolfSSL_SendUserCanceled), /* This test needs to stay at the end to clean up any caches allocated. */ TEST_DECL(test_wolfSSL_Cleanup) }; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index f12d32a23d..f5528e3a6b 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1249,6 +1249,7 @@ WOLFSSL_API unsigned int wolfSSL_SESSION_get_max_early_data(const WOLFSSL_SESSIO WOLFSSL_ABI WOLFSSL_API void wolfSSL_CTX_free(WOLFSSL_CTX* ctx); WOLFSSL_ABI WOLFSSL_API void wolfSSL_free(WOLFSSL* ssl); WOLFSSL_ABI WOLFSSL_API int wolfSSL_shutdown(WOLFSSL* ssl); +WOLFSSL_API int wolfSSL_SendUserCanceled(WOLFSSL* ssl); WOLFSSL_API int wolfSSL_send(WOLFSSL* ssl, const void* data, int sz, int flags); WOLFSSL_API int wolfSSL_recv(WOLFSSL* ssl, void* data, int sz, int flags); @@ -2576,7 +2577,8 @@ enum { /* ssl Constants */ WOLFSSL_FAILURE = 0, /* for some functions */ WOLFSSL_SUCCESS = 1, -/* WOLFSSL_SHUTDOWN_NOT_DONE is returned by wolfSSL_shutdown when the other end +/* WOLFSSL_SHUTDOWN_NOT_DONE is returned by wolfSSL_shutdown and + * wolfSSL_SendUserCanceled when the other end * of the connection has yet to send its close notify alert as part of the * bidirectional shutdown. To complete the shutdown, either keep calling * wolfSSL_shutdown until it returns WOLFSSL_SUCCESS or call wolfSSL_read until