Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -41197,12 +41210,19 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
/* 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;
Expand Down
6 changes: 6 additions & 0 deletions src/tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
94 changes: 94 additions & 0 deletions tests/api/test_ssl_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,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,
Comment thread
dgarske marked this conversation as resolved.
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;
Expand Down
3 changes: 3 additions & 0 deletions tests/api/test_ssl_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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", \
Expand Down
34 changes: 31 additions & 3 deletions tests/api/test_tls13.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions wolfssl/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading