From: Frederic Lecaille Date: Thu, 31 Jul 2025 16:19:24 +0000 (+0200) Subject: MINOR: quic-be: modify ssl_sock_srv_try_reuse_sess() to reuse backend sessions (0... X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ebd38a8c164c2358a9c7d0049868aa9d896c9e05;p=thirdparty%2Fhaproxy.git MINOR: quic-be: modify ssl_sock_srv_try_reuse_sess() to reuse backend sessions (0-RTT) This function is called for both TCP and QUIC connections to reuse SSL sessions saved by ssl_sess_new_srv_cb() callback called upon new SSL session creation. In addition to this, a QUIC SSL session must reuse the ALPN and some specific QUIC transport parameters. This is what is added by this patch for QUIC 0-RTT sessions. Note that for now on, ssl_sock_srv_try_reuse_sess() may fail for QUIC connections if it did not managed to reuse the ALPN. The caller must be informed of such an issue. It must not enable 0-RTT for the current session in this case. This is impossible without ALPN which is required to start a mux. ssl_sock_srv_try_reuse_sess() is modified to always succeeds for TCP connections. --- diff --git a/include/haproxy/ssl_sock.h b/include/haproxy/ssl_sock.h index d421061ca..f974110fd 100644 --- a/include/haproxy/ssl_sock.h +++ b/include/haproxy/ssl_sock.h @@ -71,7 +71,7 @@ int ssl_sock_get_alpn(const struct connection *conn, void *xprt_ctx, const char **str, int *len); int ssl_bio_and_sess_init(struct connection *conn, SSL_CTX *ssl_ctx, SSL **ssl, BIO **bio, BIO_METHOD *bio_meth, void *ctx); -void ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv); +int ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv); const char *ssl_sock_get_sni(struct connection *conn); const char *ssl_sock_get_cert_sig(struct connection *conn); const char *ssl_sock_get_cipher_name(struct connection *conn); diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 70104ed23..deda64812 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -5663,9 +5663,23 @@ int increment_sslconn() /* Try to reuse an SSL session (SSL_SESSION object) for server with * as SSL socket context. + * Return 1 if succeeded, 0 if not. Always succeeds for TCP socket. May fail + * for QUIC sockets. */ -void ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv) +int ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv) { +#ifdef USE_QUIC + struct quic_conn *qc = ctx->qc; + /* Default status for QUIC sockets + 0-RTT is failure(0). The status will + * be set to success(1) only if the QUIC connection parameters + * (transport parameters and ALPN) are successfully reused. + */ + int ret = qc && (srv->ssl_ctx.options & SRV_SSL_O_EARLY_DATA) ? 0 : 1; +#else + /* Always succeeds for TCP sockets. */ + int ret = 1; +#endif + HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.lock); if (srv->ssl_ctx.reused_sess[tid].ptr) { /* let's recreate a session from (ptr,size) and assign @@ -5684,6 +5698,9 @@ void ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv) SSL_SESSION_free(sess); HA_RWLOCK_WRLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[tid].sess_lock); ha_free(&srv->ssl_ctx.reused_sess[tid].ptr); +#ifdef USE_QUIC + ha_free(&srv->ssl_ctx.reused_sess[tid].alpn); +#endif HA_RWLOCK_WRTORD(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[tid].sess_lock); if (srv->ssl_ctx.reused_sess[tid].sni) SSL_set_tlsext_host_name(ctx->ssl, srv->ssl_ctx.reused_sess[tid].sni); @@ -5694,6 +5711,18 @@ void ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv) HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[tid].sess_lock); if (srv->ssl_ctx.reused_sess[tid].sni) SSL_set_tlsext_host_name(ctx->ssl, srv->ssl_ctx.reused_sess[tid].sni); +#ifdef USE_QUIC + if (qc && srv->ssl_ctx.options & SRV_SSL_O_EARLY_DATA) { + const unsigned char *alpn = + (unsigned char *)srv->ssl_ctx.reused_sess[tid].alpn; + struct quic_early_transport_params *etps = + &srv->ssl_ctx.reused_sess[tid].tps; + + if (quic_reuse_srv_params(qc, alpn, etps)) + /* Success */ + ret = 1; + } +#endif HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[tid].sess_lock); } } else { @@ -5716,6 +5745,18 @@ void ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv) if (sess) { if (!SSL_set_session(ctx->ssl, sess)) HA_ATOMIC_CAS(&srv->ssl_ctx.last_ssl_sess_tid, &old_tid, 0); // no more valid +#ifdef USE_QUIC + else if (qc && srv->ssl_ctx.options & SRV_SSL_O_EARLY_DATA) { + const unsigned char *alpn = + (unsigned char *)srv->ssl_ctx.reused_sess[old_tid-1].alpn; + struct quic_early_transport_params *etps = + &srv->ssl_ctx.reused_sess[old_tid-1].tps; + + if (quic_reuse_srv_params(qc, alpn, etps)) + /* Success */ + ret = 1; + } +#endif SSL_SESSION_free(sess); } } @@ -5727,6 +5768,8 @@ void ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv) } } HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.lock); + + return ret; } /* @@ -5774,6 +5817,9 @@ static int ssl_sock_init(struct connection *conn, void **xprt_ctx) #ifdef HA_USE_KTLS ctx->record_type = 0; #endif +#ifdef USE_QUIC + ctx->qc = NULL; +#endif next_sslconn = increment_sslconn(); if (!next_sslconn) {