diff --git a/src/internal.c b/src/internal.c index 975410b762..e382b42d0f 100644 --- a/src/internal.c +++ b/src/internal.c @@ -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; diff --git a/src/ssl_api_rw.c b/src/ssl_api_rw.c index 0c2027e709..1d0a8ce18e 100644 --- a/src/ssl_api_rw.c +++ b/src/ssl_api_rw.c @@ -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; diff --git a/src/tls13.c b/src/tls13.c index a7e306283c..acae5d5121 100644 --- a/src/tls13.c +++ b/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. */ diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index 1e9e7d95d4..20ecc20d64 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -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 diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h index 58f9c0e140..b073f01de4 100644 --- a/tests/api/test_tls13.h +++ b/tests/api/test_tls13.h @@ -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), \