From 9514b21133ae904ac805b4930449b19df725ce22 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Tue, 30 Jun 2026 16:05:22 +0200 Subject: [PATCH] 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 2e4a8952f10..367a0134f94 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 155cc09546e..3dfe4f9f0b8 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 3cd37c739bd..bf5441b6df2 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