Version
5.9.4-stable and master (checked 2026-10-02). The abort was added by #9884, so 5.9.0 and later are affected.
Description
A TLS 1.3 server with session tickets fails the handshake of a client's 256th consecutive resumption with SESSION_TICKET_NONCE_OVERFLOW (-517). This assumes the client always resumes with the newest ticket it received.
When a connection resumes from a ticket, DoClientTicketFinalize (src/internal.c) restores that ticket's nonce into ssl->session->ticketNonce, because the resumption PSK is derived from it. SendTls13NewSessionTicket (src/tls13.c) then increments that inherited value for the connection's new ticket, rather than starting at 0. Each resumption in a chain therefore adds one. Since #9884, the server aborts once the value reaches 255.
RFC 8446 §4.6.1 only requires the nonce to be "unique across all tickets issued on this connection". Each connection's tickets are derived from that connection's own resumption_master_secret, so restarting the nonce on each connection would not repeat a PSK. Before #9884 the counter wrapped silently, so this limit is new in 5.9.0.
What the client sees: the handshake completes as a resumption, then the server closes the connection without an alert. An OpenSSL client keeps the ticket after this failure, so every retry fails the same way until the ticket expires.
We hit this with a service whose clients reconnect often.
Reproduction
Stock 5.9.4-stable, macOS arm64:
./configure --enable-session-ticket --disable-shared --enable-static && make
./examples/server/server -v 4 -d -i -x -g -p 11443
Chain resumptions with OpenSSL 3.6, always resuming from the newest session:
req() { printf 'GET / HTTP/1.1\r\nHost: localhost\r\n\r\n'; sleep 0.2; }
req | openssl s_client -connect localhost:11443 -tls1_3 -ign_eof -sess_out s0.sess > c0.txt 2>&1
prev=s0.sess
for ((i=1; i<=260; i++)); do
req | openssl s_client -connect localhost:11443 -tls1_3 -ign_eof -sess_in $prev -sess_out s$i.sess > c$i.txt 2>&1
[ -s s$i.sess ] && prev=s$i.sess
done
Connections 1 to 255 report Reused, TLSv1.3 and receive the HTML page. Connection 256 reports Reused, TLSv1.3 and receives nothing, and the server prints:
SSL_accept error -517, Session ticket nonce overflow
Every later connection fails the same way, because no new ticket was issued.
Expected
A client can keep resuming indefinitely. Each connection's ticket nonces start at 0, or at least the nonce restored from the resumed ticket is not used as the starting point of the counter.
Possible fix
Derive the nonce for tickets sent on a connection from a per-connection counter (for example ssl->options.ticketsSent), rather than from ssl->session->ticketNonce as restored from the resumed ticket. Alternatively, reset ssl->session->ticketNonce on the server once the resumption PSK has been derived.
Workaround
wolfSSL_CTX_no_ticket_TLSv13() on the server context. TLS 1.3 clients then do a full handshake on every connection.
Version
5.9.4-stable and master (checked 2026-10-02). The abort was added by #9884, so 5.9.0 and later are affected.
Description
A TLS 1.3 server with session tickets fails the handshake of a client's 256th consecutive resumption with
SESSION_TICKET_NONCE_OVERFLOW(-517). This assumes the client always resumes with the newest ticket it received.When a connection resumes from a ticket,
DoClientTicketFinalize(src/internal.c) restores that ticket's nonce intossl->session->ticketNonce, because the resumption PSK is derived from it.SendTls13NewSessionTicket(src/tls13.c) then increments that inherited value for the connection's new ticket, rather than starting at 0. Each resumption in a chain therefore adds one. Since #9884, the server aborts once the value reaches 255.RFC 8446 §4.6.1 only requires the nonce to be "unique across all tickets issued on this connection". Each connection's tickets are derived from that connection's own resumption_master_secret, so restarting the nonce on each connection would not repeat a PSK. Before #9884 the counter wrapped silently, so this limit is new in 5.9.0.
What the client sees: the handshake completes as a resumption, then the server closes the connection without an alert. An OpenSSL client keeps the ticket after this failure, so every retry fails the same way until the ticket expires.
We hit this with a service whose clients reconnect often.
Reproduction
Stock 5.9.4-stable, macOS arm64:
Chain resumptions with OpenSSL 3.6, always resuming from the newest session:
Connections 1 to 255 report
Reused, TLSv1.3and receive the HTML page. Connection 256 reportsReused, TLSv1.3and receives nothing, and the server prints:Every later connection fails the same way, because no new ticket was issued.
Expected
A client can keep resuming indefinitely. Each connection's ticket nonces start at 0, or at least the nonce restored from the resumed ticket is not used as the starting point of the counter.
Possible fix
Derive the nonce for tickets sent on a connection from a per-connection counter (for example
ssl->options.ticketsSent), rather than fromssl->session->ticketNonceas restored from the resumed ticket. Alternatively, resetssl->session->ticketNonceon the server once the resumption PSK has been derived.Workaround
wolfSSL_CTX_no_ticket_TLSv13()on the server context. TLS 1.3 clients then do a full handshake on every connection.