From 9514b21133ae904ac805b4930449b19df725ce22 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 30 Jun 2026 16:05:22 +0200 Subject: [PATCH 1/3] Cap session ticket lifetime hint at half of key lifetime The default ticket encryption callback rotates two keys and can only honor a hint below WOLFSSL_TICKET_KEY_LIFETIME/2; a larger hint previously left no key available for encryption, failing every handshake after the first on a reused server CTX. Now these values are rejected. --- src/ssl_api_ext.c | 11 +++++++++++ tests/api/test_ssl_ext.c | 11 +++++++++++ wolfssl/internal.h | 4 ++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/ssl_api_ext.c b/src/ssl_api_ext.c index 2e4a8952f1..367a0134f9 100644 --- a/src/ssl_api_ext.c +++ b/src/ssl_api_ext.c @@ -1055,6 +1055,8 @@ int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) * * @param [in] ctx SSL/TLS context object. * @param [in] hint Lifetime hint in seconds. No more than 604800 (7 days). + * With the default ticket encryption callback, must also be + * less than WOLFSSL_TICKET_KEY_LIFETIME / 2. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when ctx is NULL or hint is out of range. */ @@ -1068,6 +1070,15 @@ int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) if (hint < 0 || hint > 604800) return BAD_FUNC_ARG; +#ifdef WOLFSSL_TICKET_KEY_LIFETIME + /* The default ticket encryption callback rotates two keys, each living + * WOLFSSL_TICKET_KEY_LIFETIME seconds. Its staggered rotation can only + * honor a hint below half that; a larger hint would leave no key available + * for encryption. */ + if (hint >= WOLFSSL_TICKET_KEY_LIFETIME / 2) + return BAD_FUNC_ARG; +#endif + ctx->ticketHint = hint; return WOLFSSL_SUCCESS; diff --git a/tests/api/test_ssl_ext.c b/tests/api/test_ssl_ext.c index 155cc09546..3dfe4f9f0b 100644 --- a/tests/api/test_ssl_ext.c +++ b/tests/api/test_ssl_ext.c @@ -188,7 +188,18 @@ int test_wolfSSL_CTX_set_TicketHint_ext(void) ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604801), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 0), WOLFSSL_SUCCESS); +#ifdef WOLFSSL_TICKET_KEY_LIFETIME + /* The default ticket encryption callback can only honor a hint below half + * the ticket key lifetime; larger values are rejected. */ + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, WOLFSSL_TICKET_KEY_LIFETIME / 2), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, + WOLFSSL_TICKET_KEY_LIFETIME / 2 - 1), WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604800), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); +#else ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604800), WOLFSSL_SUCCESS); +#endif wolfSSL_CTX_free(ctx); #endif diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 3cd37c739b..bf5441b6df 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2047,8 +2047,8 @@ WOLFSSL_LOCAL int NamedGroupIsPqcHybrid(int group); /* Default lifetime is 1 hour from issue of first ticket with key. */ #define WOLFSSL_TICKET_KEY_LIFETIME (60 * 60) #endif - #if WOLFSSL_TICKET_KEY_LIFETIME <= SESSION_TICKET_HINT_DEFAULT - #error "Ticket Key lifetime must be longer than ticket life hint." + #if WOLFSSL_TICKET_KEY_LIFETIME <= 2 * SESSION_TICKET_HINT_DEFAULT + #error "Ticket Key lifetime must be more than twice the ticket life hint." #endif #endif From bd7db08967047e6f1b7ef5ed952b3071a1551c9d Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 8 Jul 2026 06:17:36 +0200 Subject: [PATCH 2/3] Move ticket hint check to default callback --- src/internal.c | 7 ++++ src/ssl_api_ext.c | 11 ------ tests/api/test_ssl_ext.c | 82 ++++++++++++++++++++++++++++++++++------ tests/api/test_ssl_ext.h | 3 ++ tests/api/test_tls13.c | 34 +++++++++++++++-- wolfssl/internal.h | 4 +- 6 files changed, 114 insertions(+), 27 deletions(-) diff --git a/src/internal.c b/src/internal.c index fed9d370de..6b031c5e40 100644 --- a/src/internal.c +++ b/src/internal.c @@ -41744,6 +41744,13 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ], return BUFFER_E; } + /* The two-key rotation can only honor a hint below half the key lifetime. + * Refuse to issue a ticket whose advertised lifetime it cannot cover. */ + if (enc && 2 * ctx->ticketHint >= WOLFSSL_TICKET_KEY_LIFETIME) { + WOLFSSL_MSG("Ticket hint exceeds half the ticket key lifetime"); + return WOLFSSL_TICKET_RET_FATAL; + } + /* Check we have setup the RNG, name and primary key. */ if (keyCtx->expirary[0] == 0) { #ifndef SINGLE_THREADED diff --git a/src/ssl_api_ext.c b/src/ssl_api_ext.c index 367a0134f9..2e4a8952f1 100644 --- a/src/ssl_api_ext.c +++ b/src/ssl_api_ext.c @@ -1055,8 +1055,6 @@ int wolfSSL_CTX_set_TicketEncCb(WOLFSSL_CTX* ctx, SessionTicketEncCb cb) * * @param [in] ctx SSL/TLS context object. * @param [in] hint Lifetime hint in seconds. No more than 604800 (7 days). - * With the default ticket encryption callback, must also be - * less than WOLFSSL_TICKET_KEY_LIFETIME / 2. * @return WOLFSSL_SUCCESS on success. * @return BAD_FUNC_ARG when ctx is NULL or hint is out of range. */ @@ -1070,15 +1068,6 @@ int wolfSSL_CTX_set_TicketHint(WOLFSSL_CTX* ctx, int hint) if (hint < 0 || hint > 604800) return BAD_FUNC_ARG; -#ifdef WOLFSSL_TICKET_KEY_LIFETIME - /* The default ticket encryption callback rotates two keys, each living - * WOLFSSL_TICKET_KEY_LIFETIME seconds. Its staggered rotation can only - * honor a hint below half that; a larger hint would leave no key available - * for encryption. */ - if (hint >= WOLFSSL_TICKET_KEY_LIFETIME / 2) - return BAD_FUNC_ARG; -#endif - ctx->ticketHint = hint; return WOLFSSL_SUCCESS; diff --git a/tests/api/test_ssl_ext.c b/tests/api/test_ssl_ext.c index 3dfe4f9f0b..2fad00986d 100644 --- a/tests/api/test_ssl_ext.c +++ b/tests/api/test_ssl_ext.c @@ -188,24 +188,84 @@ int test_wolfSSL_CTX_set_TicketHint_ext(void) ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604801), WC_NO_ERR_TRACE(BAD_FUNC_ARG)); ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 0), WOLFSSL_SUCCESS); -#ifdef WOLFSSL_TICKET_KEY_LIFETIME - /* The default ticket encryption callback can only honor a hint below half - * the ticket key lifetime; larger values are rejected. */ - ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, WOLFSSL_TICKET_KEY_LIFETIME / 2), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); - ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, - WOLFSSL_TICKET_KEY_LIFETIME / 2 - 1), WOLFSSL_SUCCESS); - ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604800), - WC_NO_ERR_TRACE(BAD_FUNC_ARG)); -#else ExpectIntEQ(wolfSSL_CTX_set_TicketHint(ctx, 604800), WOLFSSL_SUCCESS); -#endif wolfSSL_CTX_free(ctx); #endif return EXPECT_RESULT(); } +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) \ + && defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) \ + && !defined(NO_WOLFSSL_SERVER) +/* Trivial custom ticket encryption callback: it has no key-lifetime constraint, + * so it must be able to issue a ticket for any hint. */ +static int test_TicketHint_custom_encCb(WOLFSSL* ssl, + byte key_name[WOLFSSL_TICKET_NAME_SZ], byte iv[WOLFSSL_TICKET_IV_SZ], + byte mac[WOLFSSL_TICKET_MAC_SZ], int enc, byte* ticket, int inLen, + int* outLen, void* userCtx) +{ + int i; + (void)ssl; + (void)userCtx; + if (enc) { + XMEMSET(key_name, 0x2A, WOLFSSL_TICKET_NAME_SZ); + XMEMSET(iv, 0x2A, WOLFSSL_TICKET_IV_SZ); + XMEMSET(mac, 0x2A, WOLFSSL_TICKET_MAC_SZ); + } + for (i = 0; i < inLen; i++) + ticket[i] = (byte)(ticket[i] ^ 0xA5); + *outLen = inLen; + return WOLFSSL_TICKET_RET_OK; +} + +/* Drive one TLS 1.3 handshake, returning the handshake result. */ +static int test_TicketHint_handshake(int hint, int customCb) +{ + struct test_memio_ctx test_ctx; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + int ret; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + if (test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_3_client_method, wolfTLSv1_3_server_method) != 0) { + ret = -1; + goto done; + } + if (customCb) + wolfSSL_CTX_set_TicketEncCb(ctx_s, test_TicketHint_custom_encCb); + wolfSSL_CTX_set_TicketHint(ctx_s, hint); + + ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); +done: + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); + return ret; +} +#endif + +/* The default ticket encryption callback must refuse to issue a ticket when the + * hint exceeds half the key lifetime, but a custom callback has no such limit. */ +int test_wolfSSL_CTX_set_TicketHint_default_cb_limit(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) \ + && defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) \ + && !defined(NO_WOLFSSL_SERVER) + /* Default callback: a hint below the limit is honored. */ + ExpectIntEQ(test_TicketHint_handshake(WOLFSSL_TICKET_KEY_LIFETIME / 2 - 1, 0), + 0); + /* Default callback: a hint at/above the limit fails the handshake. */ + ExpectIntNE(test_TicketHint_handshake(WOLFSSL_TICKET_KEY_LIFETIME / 2, 0), 0); + /* Custom callback: the same oversized hint is fine. */ + ExpectIntEQ(test_TicketHint_handshake(WOLFSSL_TICKET_KEY_LIFETIME / 2, 1), 0); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_tlsext_max_fragment_length_ext(void) { EXPECT_DECLS; diff --git a/tests/api/test_ssl_ext.h b/tests/api/test_ssl_ext.h index ffb42f5fc8..db0de04c2e 100644 --- a/tests/api/test_ssl_ext.h +++ b/tests/api/test_ssl_ext.h @@ -28,6 +28,7 @@ int test_wolfSSL_CTX_num_tickets_ext(void); int test_wolfSSL_set1_groups_ext(void); int test_wolfSSL_set1_groups_list_ext(void); int test_wolfSSL_CTX_set_TicketHint_ext(void); +int test_wolfSSL_CTX_set_TicketHint_default_cb_limit(void); int test_wolfSSL_tlsext_max_fragment_length_ext(void); int test_wolfSSL_DisableExtendedMasterSecret_ext(void); int test_wolfSSL_set_tlsext_host_name_ext(void); @@ -57,6 +58,8 @@ int test_wolfSSL_CTX_set_alpn_protos_inval_ext(void); TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_groups_ext), \ TEST_DECL_GROUP("ssl_ext", test_wolfSSL_set1_groups_list_ext), \ TEST_DECL_GROUP("ssl_ext", test_wolfSSL_CTX_set_TicketHint_ext), \ + TEST_DECL_GROUP("ssl_ext", \ + test_wolfSSL_CTX_set_TicketHint_default_cb_limit), \ TEST_DECL_GROUP("ssl_ext", \ test_wolfSSL_tlsext_max_fragment_length_ext), \ TEST_DECL_GROUP("ssl_ext", \ diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c index e4d5c3821d..f3bf53e459 100644 --- a/tests/api/test_tls13.c +++ b/tests/api/test_tls13.c @@ -5729,12 +5729,38 @@ int test_tls13_short_session_ticket(void) } +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_TLS13) && defined(HAVE_SESSION_TICKET) +/* Custom ticket encryption callback with no key-lifetime limit, so the server + * issues a ticket for any hint (the default callback refuses a hint of at least + * half the key lifetime). */ +static int test_tls13_max_lifetime_ticketEncCb(WOLFSSL* ssl, + byte key_name[WOLFSSL_TICKET_NAME_SZ], byte iv[WOLFSSL_TICKET_IV_SZ], + byte mac[WOLFSSL_TICKET_MAC_SZ], int enc, byte* ticket, int inLen, + int* outLen, void* userCtx) +{ + int i; + (void)ssl; + (void)userCtx; + if (enc) { + XMEMSET(key_name, 0x2A, WOLFSSL_TICKET_NAME_SZ); + XMEMSET(iv, 0x2A, WOLFSSL_TICKET_IV_SZ); + XMEMSET(mac, 0x2A, WOLFSSL_TICKET_MAC_SZ); + } + for (i = 0; i < inLen; i++) + ticket[i] = (byte)(ticket[i] ^ 0xA5); + *outLen = inLen; + return WOLFSSL_TICKET_RET_OK; +} +#endif + /* RFC 8446 Section 4.6.1: a NewSessionTicket lifetime greater than * MAX_LIFETIME (604800 seconds, 7 days) must be rejected. The public * wolfSSL_CTX_set_TicketHint setter clamps the value, so write the - * out-of-range hint directly into the server CTX to force the server to - * encode an over-limit lifetime onto the wire and confirm the client's - * DoTls13NewSessionTicket bound check fires. */ + * out-of-range hint directly into the server CTX. A custom encryption callback + * is installed so the default callback's key-lifetime limit does not block + * issuance, forcing the server to encode the over-limit lifetime onto the wire + * and confirming the client's DoTls13NewSessionTicket bound check fires. */ int test_tls13_new_session_ticket_max_lifetime(void) { EXPECT_DECLS; @@ -5749,6 +5775,8 @@ int test_tls13_new_session_ticket_max_lifetime(void) ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0); + wolfSSL_CTX_set_TicketEncCb(ctx_s, test_tls13_max_lifetime_ticketEncCb); + /* Bypass the public-API clamp at 604800. */ if (EXPECT_SUCCESS()) { ctx_s->ticketHint = MAX_LIFETIME + 1; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index bf5441b6df..3cd37c739b 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2047,8 +2047,8 @@ WOLFSSL_LOCAL int NamedGroupIsPqcHybrid(int group); /* Default lifetime is 1 hour from issue of first ticket with key. */ #define WOLFSSL_TICKET_KEY_LIFETIME (60 * 60) #endif - #if WOLFSSL_TICKET_KEY_LIFETIME <= 2 * SESSION_TICKET_HINT_DEFAULT - #error "Ticket Key lifetime must be more than twice the ticket life hint." + #if WOLFSSL_TICKET_KEY_LIFETIME <= SESSION_TICKET_HINT_DEFAULT + #error "Ticket Key lifetime must be longer than ticket life hint." #endif #endif From 207b8c137c1e437234862e28fee898c60513145b Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Wed, 8 Jul 2026 22:44:33 +0200 Subject: [PATCH 3/3] Continue without ticket rather than failing handshake --- src/internal.c | 39 ++++++++++++++++++++++------------ src/tls13.c | 6 ++++++ tests/api/test_ssl_ext.c | 45 ++++++++++++++++++++++++++++++---------- wolfssl/internal.h | 1 + 4 files changed, 67 insertions(+), 24 deletions(-) diff --git a/src/internal.c b/src/internal.c index 6b031c5e40..dffac1e38d 100644 --- a/src/internal.c +++ b/src/internal.c @@ -40181,6 +40181,19 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl) } #endif + /* Returns 1 when the default ticket encryption callback is in use with a + * hint of at least half the key lifetime. */ + int DefTicketHintTooLarge(WOLFSSL* ssl) + { + #if !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) && !defined(NO_WOLFSSL_SERVER) + return ssl->ctx->ticketEncCb == DefTicketEncCb && + 2 * ssl->ctx->ticketHint >= WOLFSSL_TICKET_KEY_LIFETIME; + #else + (void)ssl; + return 0; + #endif + } + /* create a new session ticket, 0 on success * Do any kind of setup in SetupTicket */ int CreateTicket(WOLFSSL* ssl) @@ -41197,12 +41210,19 @@ cleanup: /* This will be set when SendHandshakeMsg returns WANT_WRITE. Create * a new ticket only once. */ !ssl->options.buildingMsg) { - ret = SetupTicket(ssl); - if (ret != 0) - return ret; - ret = CreateTicket(ssl); - if (ret != 0) - return ret; + if (DefTicketHintTooLarge(ssl)) { + WOLFSSL_MSG("Ticket hint exceeds half the ticket key lifetime; " + "skipping ticket"); + ssl->session->ticketLen = 0; + } + else { + ret = SetupTicket(ssl); + if (ret != 0) + return ret; + ret = CreateTicket(ssl); + if (ret != 0) + return ret; + } } length += ssl->session->ticketLen; @@ -41744,13 +41764,6 @@ static int DefTicketEncCb(WOLFSSL* ssl, byte key_name[WOLFSSL_TICKET_NAME_SZ], return BUFFER_E; } - /* The two-key rotation can only honor a hint below half the key lifetime. - * Refuse to issue a ticket whose advertised lifetime it cannot cover. */ - if (enc && 2 * ctx->ticketHint >= WOLFSSL_TICKET_KEY_LIFETIME) { - WOLFSSL_MSG("Ticket hint exceeds half the ticket key lifetime"); - return WOLFSSL_TICKET_RET_FATAL; - } - /* Check we have setup the RNG, name and primary key. */ if (keyCtx->expirary[0] == 0) { #ifndef SINGLE_THREADED diff --git a/src/tls13.c b/src/tls13.c index ecfd5946dd..5d99b91483 100644 --- a/src/tls13.c +++ b/src/tls13.c @@ -12887,6 +12887,12 @@ static int SendTls13NewSessionTicket(WOLFSSL* ssl) WOLFSSL_START(WC_FUNC_NEW_SESSION_TICKET_SEND); WOLFSSL_ENTER("SendTls13NewSessionTicket"); + if (DefTicketHintTooLarge(ssl)) { + WOLFSSL_MSG("Ticket hint exceeds half the ticket key lifetime; " + "skipping ticket"); + return 0; + } + #ifdef WOLFSSL_DTLS13 if (ssl->options.dtls) idx = Dtls13GetRlHeaderLength(ssl, 1) + DTLS_HANDSHAKE_HEADER_SZ; diff --git a/tests/api/test_ssl_ext.c b/tests/api/test_ssl_ext.c index 2fad00986d..8a138e5045 100644 --- a/tests/api/test_ssl_ext.c +++ b/tests/api/test_ssl_ext.c @@ -219,25 +219,37 @@ static int test_TicketHint_custom_encCb(WOLFSSL* ssl, return WOLFSSL_TICKET_RET_OK; } -/* Drive one TLS 1.3 handshake, returning the handshake result. */ -static int test_TicketHint_handshake(int hint, int customCb) +/* Run a handshake with the given hint (optionally with the custom callback), + * process any (post-handshake) NewSessionTicket, and return the ticket length + * the client received: -1 if the handshake failed, 0 if it completed without a + * ticket, >0 if a ticket was issued. */ +static int test_TicketHint_client_ticket_len(method_provider client_meth, + method_provider server_meth, int hint, int customCb) { struct test_memio_ctx test_ctx; WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + char buf[64]; int ret; XMEMSET(&test_ctx, 0, sizeof(test_ctx)); if (test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, - wolfTLSv1_3_client_method, wolfTLSv1_3_server_method) != 0) { + client_meth, server_meth) != 0) { ret = -1; goto done; } + wolfSSL_UseSessionTicket(ssl_c); if (customCb) wolfSSL_CTX_set_TicketEncCb(ctx_s, test_TicketHint_custom_encCb); wolfSSL_CTX_set_TicketHint(ctx_s, hint); - ret = test_memio_do_handshake(ssl_c, ssl_s, 10, NULL); + if (test_memio_do_handshake(ssl_c, ssl_s, 10, NULL) != 0) { + ret = -1; + goto done; + } + /* Drive the client to process a post-handshake NewSessionTicket, if any. */ + (void)wolfSSL_read(ssl_c, buf, sizeof(buf)); + ret = ssl_c->session->ticketLen; done: wolfSSL_free(ssl_c); wolfSSL_free(ssl_s); @@ -255,13 +267,24 @@ int test_wolfSSL_CTX_set_TicketHint_default_cb_limit(void) #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) \ && defined(HAVE_SESSION_TICKET) && !defined(WOLFSSL_NO_DEF_TICKET_ENC_CB) \ && !defined(NO_WOLFSSL_SERVER) - /* Default callback: a hint below the limit is honored. */ - ExpectIntEQ(test_TicketHint_handshake(WOLFSSL_TICKET_KEY_LIFETIME / 2 - 1, 0), - 0); - /* Default callback: a hint at/above the limit fails the handshake. */ - ExpectIntNE(test_TicketHint_handshake(WOLFSSL_TICKET_KEY_LIFETIME / 2, 0), 0); - /* Custom callback: the same oversized hint is fine. */ - ExpectIntEQ(test_TicketHint_handshake(WOLFSSL_TICKET_KEY_LIFETIME / 2, 1), 0); + /* Default callback, hint below the limit: handshake succeeds, ticket issued. */ + ExpectIntGT(test_TicketHint_client_ticket_len(wolfTLSv1_3_client_method, + wolfTLSv1_3_server_method, WOLFSSL_TICKET_KEY_LIFETIME / 2 - 1, 0), 0); + /* Default callback, hint at the limit: handshake succeeds, no ticket. */ + ExpectIntEQ(test_TicketHint_client_ticket_len(wolfTLSv1_3_client_method, + wolfTLSv1_3_server_method, WOLFSSL_TICKET_KEY_LIFETIME / 2, 0), 0); + /* Custom callback: the same oversized hint still issues a ticket. */ + ExpectIntGT(test_TicketHint_client_ticket_len(wolfTLSv1_3_client_method, + wolfTLSv1_3_server_method, WOLFSSL_TICKET_KEY_LIFETIME / 2, 1), 0); +#ifndef WOLFSSL_NO_TLS12 + /* Same behavior on the TLS 1.2 SendTicket path. */ + ExpectIntGT(test_TicketHint_client_ticket_len(wolfTLSv1_2_client_method, + wolfTLSv1_2_server_method, WOLFSSL_TICKET_KEY_LIFETIME / 2 - 1, 0), 0); + ExpectIntEQ(test_TicketHint_client_ticket_len(wolfTLSv1_2_client_method, + wolfTLSv1_2_server_method, WOLFSSL_TICKET_KEY_LIFETIME / 2, 0), 0); + ExpectIntGT(test_TicketHint_client_ticket_len(wolfTLSv1_2_client_method, + wolfTLSv1_2_server_method, WOLFSSL_TICKET_KEY_LIFETIME / 2, 1), 0); +#endif #endif return EXPECT_RESULT(); } diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 3cd37c739b..4e8e694bf9 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2247,6 +2247,7 @@ WOLFSSL_LOCAL void CopyDecodedName(WOLFSSL_X509_NAME* name, DecodedCert* dCert, #endif WOLFSSL_LOCAL int SetupTicket(WOLFSSL* ssl); WOLFSSL_LOCAL int CreateTicket(WOLFSSL* ssl); +WOLFSSL_LOCAL int DefTicketHintTooLarge(WOLFSSL* ssl); WOLFSSL_LOCAL int HashRaw(WOLFSSL* ssl, const byte* data, int sz); WOLFSSL_LOCAL int HashOutput(WOLFSSL* ssl, const byte* output, int sz, int ivSz);