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.
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)
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;
}