Skip to content

Commit 1e46767

Browse files
committed
Address review: make the 0-RTT fresh start check clock-safe
TimeNowInMilliseconds() reports failure as 0. InitSSL_Ctx stored that as a real timestamp, which under WOLFSSL_32BIT_MILLI_TIME made every ticket look like it predated the ctx. Treat a 0 return as "no clock" and skip the check. The WOLFSSL_32BIT_MILLI_TIME comparison keyed its wrap window to the ctx uptime rather than the ticket age, so once the ctx had been alive longer than 2^31 ms (~24.9 days) it flagged its own fresh tickets and rejected all 0-RTT from then on. Bound both the ctx age and the ticket delta by the max ticket age instead: past that age DoClientTicketCheck has already rejected anything that could predate the ctx. Document that the check needs a restart-comparable clock. Ports whose millisecond clock counts from boot restart it near zero, so the check does not fire for tickets minted before a reboot.
1 parent 88d4bdf commit 1e46767

2 files changed

Lines changed: 25 additions & 4 deletions

File tree

src/internal.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2662,7 +2662,14 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap)
26622662
* down to a whole second because stateful tickets only store second
26632663
* resolution. */
26642664
ctx->ticketStartTime = TimeNowInMilliseconds();
2665-
ctx->ticketStartTime -= ctx->ticketStartTime % 1000;
2665+
if (ctx->ticketStartTime == 0) {
2666+
/* TimeNowInMilliseconds() reports failure as 0. Without a reference
2667+
* point the check cannot run, so turn it off for this ctx. */
2668+
ctx->noFreshStartCheck = 1;
2669+
}
2670+
else {
2671+
ctx->ticketStartTime -= ctx->ticketStartTime % 1000;
2672+
}
26662673
#endif
26672674

26682675
#if defined(OPENSSL_EXTRA) || defined(WOLFSSL_TLS_READ_AHEAD)

src/tls13.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6641,12 +6641,22 @@ static int DoPreSharedKeys(WOLFSSL* ssl, const byte* input, word32 inputSz,
66416641
* Flag tickets minted before this ctx was created. */
66426642
if (!ssl->ctx->noFreshStartCheck) {
66436643
#ifdef WOLFSSL_32BIT_MILLI_TIME
6644-
/* Wrap-safe: the max ticket age is far below half of the
6645-
* 2^32 ms range. */
6644+
/* A 32 bit ms clock wraps every ~49.7 days, so the ctx age is
6645+
* only exact while it stays below the max ticket age. Past
6646+
* that point DoClientTicketCheck has already rejected
6647+
* anything old enough to predate the ctx, so the check can be
6648+
* skipped. A ctx that survives the wrap re-enters the window
6649+
* for one max-ticket-age span and rejects 0-RTT until it
6650+
* leaves again. */
6651+
word32 now = TimeNowInMilliseconds();
6652+
word32 ctxAge = now - ssl->ctx->ticketStartTime;
66466653
word32 delta = ssl->ctx->ticketStartTime -
66476654
ssl->session->ticketSeen;
66486655
ssl->options.ticketPredatesCtx =
6649-
(delta != 0 && delta < 0x80000000U);
6656+
(now != 0 &&
6657+
ctxAge <= (word32)TLS13_MAX_TICKET_AGE * 1000 &&
6658+
delta != 0 &&
6659+
delta <= (word32)TLS13_MAX_TICKET_AGE * 1000);
66506660
#else
66516661
ssl->options.ticketPredatesCtx =
66526662
(ssl->session->ticketSeen < ssl->ctx->ticketStartTime);
@@ -17147,6 +17157,10 @@ int wolfSSL_CTX_set_max_early_data(WOLFSSL_CTX* ctx, unsigned int sz)
1714717157
* then accepted for tickets minted before this ctx was created. Only use
1714817158
* this when the anti-replay state reliably survives server restarts.
1714917159
*
17160+
* The check needs TimeNowInMilliseconds() to be comparable across restarts.
17161+
* On ports where it counts from boot the check never fires for tickets
17162+
* minted before a reboot.
17163+
*
1715017164
* ctx The SSL/TLS CTX object.
1715117165
* returns BAD_FUNC_ARG when ctx is NULL or not TLS v1.3, SIDE_ERROR when
1715217166
* called with a client and 0 on success.

0 commit comments

Comments
 (0)