Move ticket hint check to default callback

This commit is contained in:
Mattia Moffa
2026-07-08 06:17:36 +02:00
parent 9514b21133
commit bd7db08967
6 changed files with 114 additions and 27 deletions
+7
View File
@@ -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
-11
View File
@@ -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;
+71 -11
View File
@@ -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;
+3
View File
@@ -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", \
+31 -3
View File
@@ -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;
+2 -2
View File
@@ -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