mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-10 19:50:49 +02:00
Merge pull request #10822 from mattia-moffa/20260629-ticket-hint-window-check
Fix session ticket key rotation when hint exceeds key lifetime
This commit is contained in:
+26
-6
@@ -40769,6 +40769,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)
|
||||
@@ -41785,12 +41798,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;
|
||||
|
||||
@@ -12969,6 +12969,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;
|
||||
|
||||
@@ -225,6 +225,100 @@ int test_wolfSSL_CTX_set_TicketHint_ext(void)
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
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);
|
||||
|
||||
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);
|
||||
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, 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();
|
||||
}
|
||||
|
||||
int test_wolfSSL_tlsext_max_fragment_length_ext(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
|
||||
@@ -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
@@ -6529,12 +6529,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;
|
||||
@@ -6549,6 +6575,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;
|
||||
|
||||
@@ -2251,6 +2251,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);
|
||||
|
||||
Reference in New Issue
Block a user