From e3084e7316055e13cd0fa6ccee498e2570c1a22e Mon Sep 17 00:00:00 2001 From: EdouardMalot Date: Fri, 26 Jun 2026 15:30:42 +0200 Subject: [PATCH 1/5] Fix TLS 1.3 server: don't send NewSessionTicket (resumption is unsupported) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _nx_secure_tls_1_3_server_handshake.c sent a NewSessionTicket after every Client Finished, advertising session resumption to the client. But _nx_secure_tls_process_clienthello_psk_extension explicitly rejects any PSK with age != 0 (i.e. every real resumption attempt) with NX_SECURE_TLS_BAD_CLIENTHELLO_PSK_EXTENSION — the existing implementation only supports external PSKs. Net effect on clients that act on the advertised ticket (Java JSSE in particular): every other handshake fails. Conn N succeeds + caches the ticket; conn N+1 replays the ticket → server sends Alert(internal_error) → JSSE invalidates the cache; conn N+2 succeeds; loop. Fix: skip the NewSessionTicket send. The PSK consumer code stays as-is so any future external-PSK use case is unaffected. --- .../src/nx_secure_tls_1_3_server_handshake.c | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/nx_secure/src/nx_secure_tls_1_3_server_handshake.c b/nx_secure/src/nx_secure_tls_1_3_server_handshake.c index 2ae1cd1cf..c581349e5 100644 --- a/nx_secure/src/nx_secure_tls_1_3_server_handshake.c +++ b/nx_secure/src/nx_secure_tls_1_3_server_handshake.c @@ -559,20 +559,15 @@ NX_SECURE_TLS_SERVER_STATE old_server_state; /* Post-Auth server messages (if any) are sent here. */ - /* For session resumption, send a NewSessionTicket message to allow for resumption PSK to be generated. */ - status = _nx_secure_tls_allocate_handshake_packet(tls_session, packet_pool, &send_packet, wait_option); - if (status != NX_SUCCESS) - { - break; - } - - /* Populate the packet with our NewSessionTicket Message. */ - status = _nx_secure_tls_send_newsessionticket(tls_session, send_packet); - status = _nx_secure_tls_send_handshake_record(tls_session, send_packet, NX_SECURE_TLS_NEW_SESSION_TICKET, wait_option); - if(status != NX_SUCCESS) - { - break; - } + /* Do NOT send a NewSessionTicket. The PSK extension handler in + * _nx_secure_tls_process_clienthello_psk_extension explicitly + * rejects any age != 0 (i.e. every real resumption attempt) with + * NX_SECURE_TLS_BAD_CLIENTHELLO_PSK_EXTENSION — the server only + * supports external PSKs, not resumption. Sending a ticket + * anyway tells the client we DO resume; clients that act on + * that (e.g. Java JSSE) replay the ticket on the next handshake + * and the server then aborts with an Alert(internal_error), + * breaking every other connection from those clients. */ /* If we get here, the Client Finished was processed without errors and the handshake is complete. */ tls_session -> nx_secure_tls_server_state = NX_SECURE_TLS_SERVER_STATE_HANDSHAKE_FINISHED; From aca73b0828a5909117c9a1ace8e5a501b95695b0 Mon Sep 17 00:00:00 2001 From: EdouardMalot Date: Tue, 4 Aug 2026 13:33:00 +0200 Subject: [PATCH 2/5] Trim the source comment left by the NewSessionTicket removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The comment that replaced the removed block ended up carrying the whole incident story: the JSSE trigger, the alert path, why the stub was harmful. That belongs in the commit that made the change, not in a comment future readers will hit out of context. Keep only what the code is now. No ticket is sent because resumption is not implemented. RFC 8446 §4.6.1 makes the message optional. The PSK extension handler is the place resumption would also need to change. --- nx_secure/src/nx_secure_tls_1_3_server_handshake.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/nx_secure/src/nx_secure_tls_1_3_server_handshake.c b/nx_secure/src/nx_secure_tls_1_3_server_handshake.c index c581349e5..94d39bf86 100644 --- a/nx_secure/src/nx_secure_tls_1_3_server_handshake.c +++ b/nx_secure/src/nx_secure_tls_1_3_server_handshake.c @@ -559,15 +559,11 @@ NX_SECURE_TLS_SERVER_STATE old_server_state; /* Post-Auth server messages (if any) are sent here. */ - /* Do NOT send a NewSessionTicket. The PSK extension handler in - * _nx_secure_tls_process_clienthello_psk_extension explicitly - * rejects any age != 0 (i.e. every real resumption attempt) with - * NX_SECURE_TLS_BAD_CLIENTHELLO_PSK_EXTENSION — the server only - * supports external PSKs, not resumption. Sending a ticket - * anyway tells the client we DO resume; clients that act on - * that (e.g. Java JSSE) replay the ticket on the next handshake - * and the server then aborts with an Alert(internal_error), - * breaking every other connection from those clients. */ + /* No NewSessionTicket is sent: session resumption is not + * implemented on this server, and the message is optional per + * RFC 8446 Section 4.6.1. The corresponding rejection path + * lives in _nx_secure_tls_process_clienthello_psk_extension, + * which is where resumption support would also need to land. */ /* If we get here, the Client Finished was processed without errors and the handshake is complete. */ tls_session -> nx_secure_tls_server_state = NX_SECURE_TLS_SERVER_STATE_HANDSHAKE_FINISHED; From 725f44ab6cfe4e7ac2240ab612d97d0683f84199 Mon Sep 17 00:00:00 2001 From: EdouardMalot Date: Tue, 4 Aug 2026 13:36:15 +0200 Subject: [PATCH 3/5] Document why send_newsessionticket is now uncalled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the previous fix, this function has no callers in the library. That is deliberate: it stays as a starting point for real TLS 1.3 session resumption when someone gets to it. Without a note, the next dead-code sweep will find an unreferenced global and reasonably propose deleting it. Add a NOTE in the header block spelling out three things. The function is kept on purpose, not by accident. The ticket it builds is a placeholder — no server state, fixed identity string — so it cannot be used as is. And the reasoning for not calling it lives in the server handshake, with the RFC 8446 pointer for the fact that the message is optional. CALLED BY is updated to match. --- nx_secure/src/nx_secure_tls_send_newsessionticket.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/nx_secure/src/nx_secure_tls_send_newsessionticket.c b/nx_secure/src/nx_secure_tls_send_newsessionticket.c index 824ef273a..4b74c175d 100644 --- a/nx_secure/src/nx_secure_tls_send_newsessionticket.c +++ b/nx_secure/src/nx_secure_tls_send_newsessionticket.c @@ -41,6 +41,14 @@ /* for session resumption should the same client attempt another */ /* connection within the lifespan of the ticket. */ /* */ +/* NOTE: this function is currently uncalled. It is retained for a */ +/* future implementation of TLS 1.3 session resumption. The ticket it */ +/* builds today is a placeholder: no server-side state is stored, and */ +/* the ticket identity is a fixed string, so a client that replayed it */ +/* would be rejected. See _nx_secure_tls_1_3_server_handshake for the */ +/* reason it is not called and RFC 8446 Section 4.6.1 for the fact */ +/* that sending NewSessionTicket is optional. */ +/* */ /* INPUT */ /* */ /* tls_session TLS control block */ @@ -56,7 +64,7 @@ /* */ /* CALLED BY */ /* */ -/* _nx_secure_tls_server_handshake TLS server state machine */ +/* (none - retained for future session resumption support) */ /* */ /**************************************************************************/ #if (NX_SECURE_TLS_TLS_1_3_ENABLED) From cae8841e82e964ad5fc8d009a3289a419477ba60 Mon Sep 17 00:00:00 2001 From: EdouardMalot Date: Tue, 4 Aug 2026 13:39:51 +0200 Subject: [PATCH 4/5] Exclude send_newsessionticket from coverage reports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix left this file with no callers. Under any coverage config that compiles TLS 1.3 — tls_1_3_enable_build_coverage and sesip_build_coverage — it now reports 0% across the board. CI does not enforce a threshold, so nothing fails, but the project aims for 100% and a file going to zero is not the shape we want. Add a small common exclude list, applied to every coverage run, containing just this file. The reason it is dead is documented in its own header block, and referencing that keeps the two pieces of information in sync. The default_build_coverage block is unchanged. --- test/cmake/nx_secure/coverage.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/cmake/nx_secure/coverage.sh b/test/cmake/nx_secure/coverage.sh index a22336f97..2b69c3fdf 100755 --- a/test/cmake/nx_secure/coverage.sh +++ b/test/cmake/nx_secure/coverage.sh @@ -17,6 +17,17 @@ cd $(dirname $0) root_path=$(cd ../../../nx_secure/src; pwd) mkdir -p coverage_report/$1 extra_args="" +# Always excluded: retained for a future TLS 1.3 session-resumption +# implementation but currently uncalled. See the header block of +# nx_secure_tls_send_newsessionticket.c and PR #403 for the reason. +common_exclude_list="nx_secure_tls_send_newsessionticket.c" +for e in $common_exclude_list +do + for f in $(ls $root_path/$e); + do + extra_args+="-e $f " + done +done if [ "$1" == "default_build_coverage" ]; then exclude_list="nx*_secure_dtls_*.c \ From dfa4c28d185d3d8d2517c9b627ac68ef2e53c717 Mon Sep 17 00:00:00 2001 From: EdouardMalot Date: Tue, 4 Aug 2026 14:17:53 +0200 Subject: [PATCH 5/5] Add regression test asserting no NewSessionTicket after handshake Locks in the previous fix. The test completes a full TLS 1.3 handshake between a NetX client and a NetX server, gives the server one periodic tick to flush anything queued after client Finished, then peeks the client's raw TCP receive queue with NX_NO_WAIT. In the fixed server nothing arrives. In the pre-fix server the stub NewSessionTicket record lands there and the peek returns NX_SUCCESS instead of NX_NO_PACKET. The peek runs on the raw socket rather than through nx_secure_tls_session_receive, because the TLS layer would consume a post-handshake NewSessionTicket silently and we could not tell the difference. A semaphore holds the server side open until the client has done its check, so the server's close_notify does not pollute the peek. The half of the maintainer's ask that needs a crafted PSK-carrying ClientHello is left for the PSK-handler follow-up, per the review. --- .../cmake/nx_secure/regression/CMakeLists.txt | 1 + .../nx_secure_test/netxtestcontrol.c | 2 + ..._secure_tls_1_3_no_newsessionticket_test.c | 306 ++++++++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 test/regression/nx_secure_test/nx_secure_tls_1_3_no_newsessionticket_test.c diff --git a/test/cmake/nx_secure/regression/CMakeLists.txt b/test/cmake/nx_secure/regression/CMakeLists.txt index f6b5f0705..73bcf30d3 100644 --- a/test/cmake/nx_secure/regression/CMakeLists.txt +++ b/test/cmake/nx_secure/regression/CMakeLists.txt @@ -142,6 +142,7 @@ set(nx_secure_test_cases ${SOURCE_DIR}/nx_secure_test/nx_secure_tls_client_ca_select_test.c ${SOURCE_DIR}/nx_secure_test/nx_secure_tls_1_3_receive_invalid_server_handshake_message_test.c ${SOURCE_DIR}/nx_secure_test/nx_secure_tls_1_3_invalid_client_state_test.c + ${SOURCE_DIR}/nx_secure_test/nx_secure_tls_1_3_no_newsessionticket_test.c ${SOURCE_DIR}/nx_secure_test/nx_secure_tls_1_3_serverhello_length_checking_test.c ${SOURCE_DIR}/nx_secure_test/nx_secure_tls_1_3_session_create_ext_test.c ${SOURCE_DIR}/nx_secure_test/nx_secure_tls_1_3_before_key_generation_test.c diff --git a/test/regression/nx_secure_test/netxtestcontrol.c b/test/regression/nx_secure_test/netxtestcontrol.c index 387fb1612..1537a4e94 100644 --- a/test/regression/nx_secure_test/netxtestcontrol.c +++ b/test/regression/nx_secure_test/netxtestcontrol.c @@ -237,6 +237,7 @@ void nx_secure_tls_1_3_clienthello_length_checking_test_application_define(void void nx_secure_tls_1_3_handshake_fail_test_application_define(void *); void nx_secure_tls_1_3_hello_retry_cookie_test_application_define(void *); void nx_secure_tls_1_3_invalid_client_state_test_application_define(void *first_unused_memory); +void nx_secure_tls_1_3_no_newsessionticket_test_application_define(void *first_unused_memory); void nx_secure_tls_1_3_key_share_test_application_define(void *); void nx_secure_tls_1_3_provisioned_psk_test_application_define(void *); void nx_secure_tls_1_3_receive_invalid_server_handshake_message_test_application_define(void *); @@ -361,6 +362,7 @@ TEST_ENTRY test_control_tests[] = {nx_secure_tls_1_3_handshake_fail_test_application_define, TEST_TIMEOUT_LOW}, {nx_secure_tls_1_3_hello_retry_cookie_test_application_define, TEST_TIMEOUT_LOW}, {nx_secure_tls_1_3_invalid_client_state_test_application_define, TEST_TIMEOUT_LOW}, + {nx_secure_tls_1_3_no_newsessionticket_test_application_define, TEST_TIMEOUT_LOW}, {nx_secure_tls_1_3_key_share_test_application_define, TEST_TIMEOUT_LOW}, {nx_secure_tls_1_3_serverhello_length_checking_test_application_define, TEST_TIMEOUT_LOW}, {nx_secure_tls_1_3_session_create_ext_test_application_define, TEST_TIMEOUT_LOW}, diff --git a/test/regression/nx_secure_test/nx_secure_tls_1_3_no_newsessionticket_test.c b/test/regression/nx_secure_test/nx_secure_tls_1_3_no_newsessionticket_test.c new file mode 100644 index 000000000..3928257bd --- /dev/null +++ b/test/regression/nx_secure_test/nx_secure_tls_1_3_no_newsessionticket_test.c @@ -0,0 +1,306 @@ +/***************************************************************************/ +/* Copyright (c) 2024 Microsoft Corporation */ +/* Copyright (c) 2026 Eclipse ThreadX contributors */ +/* */ +/* This program and the accompanying materials are made available under */ +/* the terms of the MIT License which is available at */ +/* https://opensource.org/licenses/MIT. */ +/* */ +/* SPDX-License-Identifier: MIT */ +/***************************************************************************/ + +/* This test completes a TLS 1.3 handshake between a NetX client and a */ +/* NetX server and asserts that the server sends no additional record */ +/* after its Finished. The server previously emitted a stub */ +/* NewSessionTicket here; see PR #403 for the reason it was removed. */ + +#include "nx_api.h" +#include "nx_secure_tls_api.h" +#include "ecc_certs.c" + +extern VOID test_control_return(UINT status); + + +#if !defined(NX_SECURE_TLS_CLIENT_DISABLED) && !defined(NX_SECURE_TLS_SERVER_DISABLED) && defined(NX_SECURE_ENABLE_ECC_CIPHERSUITE) && (NX_SECURE_TLS_TLS_1_3_ENABLED) +#define NUM_PACKETS 24 +#define PACKET_SIZE 1536 +#define PACKET_POOL_SIZE (NUM_PACKETS * (PACKET_SIZE + sizeof(NX_PACKET))) +#define THREAD_STACK_SIZE 1024 +#define ARP_CACHE_SIZE 1024 +#define METADATA_SIZE 16000 +#define CERT_BUFFER_SIZE 2048 +#define SERVER_PORT 4433 + +/* Define the ThreadX and NetX object control blocks. */ + +static TX_THREAD thread_server; +static TX_THREAD thread_client; +static NX_PACKET_POOL pool_0; +static NX_IP ip_0; +static UINT error_counter; + +static NX_TCP_SOCKET client_socket_0; +static NX_SECURE_TLS_SESSION tls_client_session_0; +static NX_SECURE_X509_CERT client_trusted_ca; +static NX_SECURE_X509_CERT client_remote_cert; +static NX_TCP_SOCKET server_socket_0; +static NX_SECURE_TLS_SESSION tls_server_session_0; +static NX_SECURE_X509_CERT server_local_certificate; + +static ULONG pool_0_memory[PACKET_POOL_SIZE / sizeof(ULONG)]; +static ULONG thread_server_stack[THREAD_STACK_SIZE / sizeof(ULONG)]; +static ULONG thread_client_stack[THREAD_STACK_SIZE / sizeof(ULONG)]; +static ULONG ip_0_stack[THREAD_STACK_SIZE / sizeof(ULONG)]; +static ULONG arp_cache[ARP_CACHE_SIZE]; +static UCHAR client_metadata[METADATA_SIZE]; +static UCHAR server_metadata[METADATA_SIZE]; +static UCHAR client_cert_buffer[CERT_BUFFER_SIZE]; + +static UCHAR tls_packet_buffer[2][4000]; + +extern const USHORT nx_crypto_ecc_supported_groups[]; +extern const NX_CRYPTO_METHOD *nx_crypto_ecc_curves[]; +extern const UINT nx_crypto_ecc_supported_groups_size; +extern const NX_SECURE_TLS_CRYPTO nx_crypto_tls_ciphers_ecc; + +/* Signal from client to server: handshake done and the raw TCP receive + check has finished, so the server may tear down its session. */ +static TX_SEMAPHORE semaphore_check_done; + +/* Define thread prototypes. */ + +static VOID test_client_entry(ULONG thread_input); +static VOID test_server_entry(ULONG thread_input); +extern VOID _nx_ram_network_driver_1500(struct NX_IP_DRIVER_STRUCT *driver_req); + +static VOID ERROR_COUNTER(void) +{ + error_counter++; +} + +#define do_something_if_fail(p) if (!(p)) { ERROR_COUNTER(); } + +#ifdef CTEST +void test_application_define(void *first_unused_memory); +void test_application_define(void *first_unused_memory) +#else +VOID nx_secure_tls_1_3_no_newsessionticket_test_application_define(void *first_unused_memory) +#endif +{ +UINT status; +CHAR *pointer; + + error_counter = 0; + + pointer = (CHAR *)first_unused_memory; + + tx_thread_create(&thread_server, "thread server", test_server_entry, 0, + thread_server_stack, sizeof(thread_server_stack), + 7, 7, TX_NO_TIME_SLICE, TX_AUTO_START); + + tx_thread_create(&thread_client, "thread client", test_client_entry, 0, + thread_client_stack, sizeof(thread_client_stack), + 8, 8, TX_NO_TIME_SLICE, TX_AUTO_START); + + tx_semaphore_create(&semaphore_check_done, "semaphore check done", 0); + + nx_system_initialize(); + + status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", PACKET_SIZE, + pool_0_memory, PACKET_POOL_SIZE); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_ip_create(&ip_0, "NetX IP Instance 0", IP_ADDRESS(1, 2, 3, 4), 0xFFFFFF00UL, + &pool_0, _nx_ram_network_driver_1500, + ip_0_stack, sizeof(ip_0_stack), 1); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_arp_enable(&ip_0, (VOID *)arp_cache, sizeof(arp_cache)); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_tcp_enable(&ip_0); + do_something_if_fail(status == NX_SUCCESS); + + nx_secure_tls_initialize(); +} + +static VOID client_tls_setup(NX_SECURE_TLS_SESSION *tls_session_ptr) +{ +UINT status; + + memset(client_metadata, 0xFF, sizeof(client_metadata)); + status = nx_secure_tls_session_create(tls_session_ptr, + &nx_crypto_tls_ciphers_ecc, + client_metadata, + sizeof(client_metadata)); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_secure_tls_ecc_initialize(tls_session_ptr, nx_crypto_ecc_supported_groups, + nx_crypto_ecc_supported_groups_size, + nx_crypto_ecc_curves); + do_something_if_fail(status == NX_SUCCESS); + + memset(&client_remote_cert, 0, sizeof(client_remote_cert)); + status = nx_secure_tls_remote_certificate_allocate(tls_session_ptr, + &client_remote_cert, + client_cert_buffer, + sizeof(client_cert_buffer)); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_secure_x509_certificate_initialize(&client_trusted_ca, ECCA4_der, ECCA4_der_len, + NX_NULL, 0, NULL, 0, + NX_SECURE_X509_KEY_TYPE_NONE); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_secure_tls_trusted_certificate_add(tls_session_ptr, &client_trusted_ca); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_secure_tls_session_packet_buffer_set(tls_session_ptr, tls_packet_buffer[0], + sizeof(tls_packet_buffer[0])); + do_something_if_fail(status == NX_SUCCESS); +} + +static VOID server_tls_setup(NX_SECURE_TLS_SESSION *tls_session_ptr) +{ +UINT status; + + memset(server_metadata, 0xFF, sizeof(server_metadata)); + status = nx_secure_tls_session_create(tls_session_ptr, + &nx_crypto_tls_ciphers_ecc, + server_metadata, + sizeof(server_metadata)); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_secure_tls_ecc_initialize(tls_session_ptr, nx_crypto_ecc_supported_groups, + nx_crypto_ecc_supported_groups_size, + nx_crypto_ecc_curves); + do_something_if_fail(status == NX_SUCCESS); + + memset(&server_local_certificate, 0, sizeof(server_local_certificate)); + status = nx_secure_x509_certificate_initialize(&server_local_certificate, + ECTestServer4_der, ECTestServer4_der_len, + NX_NULL, 0, ECTestServer4_key_der, + ECTestServer4_key_der_len, + NX_SECURE_X509_KEY_TYPE_EC_DER); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_secure_tls_local_certificate_add(tls_session_ptr, + &server_local_certificate); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_secure_tls_session_packet_buffer_set(tls_session_ptr, tls_packet_buffer[1], + sizeof(tls_packet_buffer[1])); + do_something_if_fail(status == NX_SUCCESS); +} + +static void test_server_entry(ULONG thread_input) +{ +UINT status; + + printf("NetX Secure Test: TLS 1.3 No NewSessionTicket Test.................."); + + status = nx_tcp_socket_create(&ip_0, &server_socket_0, "Server socket", NX_IP_NORMAL, + NX_DONT_FRAGMENT, NX_IP_TIME_TO_LIVE, 8192, NX_NULL, NX_NULL); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_tcp_server_socket_listen(&ip_0, SERVER_PORT, &server_socket_0, 5, NX_NULL); + do_something_if_fail(status == NX_SUCCESS); + + server_tls_setup(&tls_server_session_0); + + status = nx_tcp_server_socket_accept(&server_socket_0, NX_WAIT_FOREVER); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_secure_tls_session_start(&tls_server_session_0, &server_socket_0, NX_WAIT_FOREVER); + do_something_if_fail(status == NX_SUCCESS); + + /* Wait for the client to finish its post-handshake check before we + tear down. Tearing down early would send a close_notify alert that + the client's raw TCP peek could observe. */ + tx_semaphore_get(&semaphore_check_done, NX_WAIT_FOREVER); + + nx_secure_tls_session_end(&tls_server_session_0, NX_IP_PERIODIC_RATE); + nx_secure_tls_session_delete(&tls_server_session_0); + + nx_tcp_socket_disconnect(&server_socket_0, NX_NO_WAIT); + nx_tcp_server_socket_unaccept(&server_socket_0); + nx_tcp_server_socket_unlisten(&ip_0, SERVER_PORT); + nx_tcp_socket_delete(&server_socket_0); +} + +static void test_client_entry(ULONG thread_input) +{ +UINT status; +NX_PACKET *packet_ptr = NX_NULL; +NXD_ADDRESS server_address; + + server_address.nxd_ip_version = NX_IP_VERSION_V4; + server_address.nxd_ip_address.v4 = IP_ADDRESS(127, 0, 0, 1); + + status = nx_tcp_socket_create(&ip_0, &client_socket_0, "Client socket", NX_IP_NORMAL, + NX_DONT_FRAGMENT, NX_IP_TIME_TO_LIVE, 8192, NX_NULL, NX_NULL); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_tcp_client_socket_bind(&client_socket_0, NX_ANY_PORT, NX_NO_WAIT); + do_something_if_fail(status == NX_SUCCESS); + + client_tls_setup(&tls_client_session_0); + + status = nxd_tcp_client_socket_connect(&client_socket_0, &server_address, SERVER_PORT, NX_WAIT_FOREVER); + do_something_if_fail(status == NX_SUCCESS); + + status = nx_secure_tls_session_start(&tls_client_session_0, &client_socket_0, NX_WAIT_FOREVER); + do_something_if_fail(status == NX_SUCCESS); + + /* Give the server thread time to run and, in the buggy case, send its + stub NewSessionTicket after processing our Finished. One periodic + tick is far more than the server needs. */ + tx_thread_sleep(NX_IP_PERIODIC_RATE); + + /* Peek the raw TCP receive queue. The TLS layer has not been asked to + receive anything since the handshake, so any bytes here must have + been sent by the server after its Finished. In the fixed server + there are none. In the buggy server there is a NewSessionTicket. */ + status = nx_tcp_socket_receive(&client_socket_0, &packet_ptr, NX_NO_WAIT); + if (status != NX_NO_PACKET) + { + ERROR_COUNTER(); + if (packet_ptr != NX_NULL) + { + nx_packet_release(packet_ptr); + } + } + + tx_semaphore_put(&semaphore_check_done); + + nx_secure_tls_session_end(&tls_client_session_0, NX_IP_PERIODIC_RATE); + nx_secure_tls_session_delete(&tls_client_session_0); + + nx_tcp_socket_disconnect(&client_socket_0, NX_NO_WAIT); + nx_tcp_client_socket_unbind(&client_socket_0); + nx_tcp_socket_delete(&client_socket_0); + + if (error_counter) + { + printf("ERROR!\n"); + test_control_return(1); + } + else + { + printf("SUCCESS!\n"); + test_control_return(0); + } +} + +#else +#ifdef CTEST +void test_application_define(void *first_unused_memory); +void test_application_define(void *first_unused_memory) +#else +VOID nx_secure_tls_1_3_no_newsessionticket_test_application_define(void *first_unused_memory) +#endif +{ + printf("NetX Secure Test: TLS 1.3 No NewSessionTicket Test..................N/A\n"); + test_control_return(3); +} +#endif