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:
committed by
Paul Adelsbach
parent
24c44ac717
commit
2fd8dc2375
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
10
src/tls13.c
10
src/tls13.c
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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), \
|
||||
|
||||
Reference in New Issue
Block a user