From: William Lallemand Date: Mon, 14 Sep 2026 12:32:05 +0000 (+0200) Subject: BUG/MEDIUM: ssl: don't set a 0 timeout on an expired TLS session X-Git-Tag: v3.5-dev7~18 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=217da687210699153f6569813c340e5131005807;p=haproxy.git BUG/MEDIUM: ssl: don't set a 0 timeout on an expired TLS session Commit 9f1d590999 ("BUG/MEDIUM: ssl: enforce tune.ssl.lifetime across TLS1.3 session renewals") clamps a resumed session's timeout to what is left of its original lifetime. Once that deadline is reached there is nothing left, and the session was given a timeout of 0. OpenSSL encodes the session timeout as an optional ASN.1 field which it omits when the value is zero, and the decoder then substitutes its own default (3 seconds) instead. construct_stateless_ticket() first measures the ticket, then re-encodes it, so the two lengths no longer match and an internal consistency check fails. The resumed handshake is aborted with an SSL_AD_INTERNAL_ERROR alert (80) instead of gracefully falling back to a full handshake: 1.1.1: error:1427D044:SSL routines:construct_stateless_ticket:internal error 3.0: error:0A0C0103:SSL routines::internal error Only OpenSSL 3.1 and older are affected, newer versions don't compare session ages in whole seconds anymore. Fix this by never handing out a zero timeout: when nothing is left of the original lifetime, clear the session's id context instead. The session then no longer matches any SSL_CTX, so OpenSSL drops it and performs a full handshake. This also makes the expired session really disappear from the stateful cache, which a 0 timeout failed to do since it was read back as the 3 seconds default. This fixes issue #3499. This must be backported as far as 2.8, where 9f1d590999 was backported. --- diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 0bc0acf43..772062f3f 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -1771,6 +1771,7 @@ static void ssl_sock_infocbk(const SSL *ssl, int where, int ret) long timeout = SSL_SESSION_get_timeout(sess); long ctx_timeout = SSL_CTX_get_timeout(SSL_get_SSL_CTX(ssl)); long elapsed = now - created; + long remaining; /* reduce the timeout if it was decreased in the configuration since the session creation */ if (ctx_timeout < timeout) @@ -1778,12 +1779,18 @@ static void ssl_sock_infocbk(const SSL *ssl, int where, int ret) if (elapsed < 0) elapsed = 0; + remaining = timeout - elapsed; + #if HA_OPENSSL_VERSION_NUMBER >= 0x30400000L SSL_SESSION_set_time_ex(sess, now); #else SSL_SESSION_set_time(sess, now); #endif - SSL_SESSION_set_timeout(sess, elapsed < timeout ? timeout - elapsed : 0); + /* reset the timeout or remove the session */ + if (remaining > 0) + SSL_SESSION_set_timeout(sess, remaining); + else + SSL_SESSION_set1_id_context(sess, (unsigned char *) "", 0); ctx->xprt_st |= SSL_SOCK_SESS_TIMEOUT_SET; }