]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic-be: Extract the code responsible of the SSL session restoration
authorFrederic Lecaille <flecaille@haproxy.com>
Tue, 22 Jul 2025 13:00:01 +0000 (15:00 +0200)
committerFrederic Lecaille <flecaille@haproxy.com>
Sat, 2 Aug 2025 08:53:39 +0000 (10:53 +0200)
This patch extracts from ssl_sock_init() the code which restores the SSL
server session which have been saved by thead by the callback set by
SSL_CTX_sess_set_new_cb() to implement ssl_sock_srv_try_reuse_sess().

Call this function when initializing the QUIC backend SSL contexts for
each connection.

include/haproxy/ssl_sock.h
src/quic_ssl.c
src/ssl_sock.c

index 84e2ed552a0b4ef73d9846bac7fcaf491de0ddbc..7c53947b1b794845c172abd3e1350a83429ef693 100644 (file)
@@ -70,6 +70,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);
 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);
index ca91fe342b33b3c724e49251f6bcbb8026c62cd0..88147a161e0ce6e75e12eadd227de268231940b6 100644 (file)
@@ -1268,6 +1268,7 @@ int qc_alloc_ssl_sock_ctx(struct quic_conn *qc, struct connection *conn)
                if (!qc_ssl_set_quic_transport_params(ctx->ssl, qc, quic_version_1, 0))
                        goto err;
 
+               ssl_sock_srv_try_reuse_sess(ctx, srv);
                SSL_set_connect_state(ctx->ssl);
                ssl_err = SSL_do_handshake(ctx->ssl);
                TRACE_PROTO("SSL_do_handshake() called", QUIC_EV_CONN_NEW, qc, &ssl_err);
index c77c82d97fce80c175db86655bca631f1efaa1a6..e5ee788aca909ed34827050b2955a051300a2b64 100644 (file)
@@ -5063,6 +5063,75 @@ int increment_sslconn()
        return next_sslconn;
 }
 
+/* Try to restore the SSL session (SSL_SESSION object) into <ctx> from them
+ * which have been stored by thread ID for <srv> server by the callback set by
+ * SSL_CTX_sess_set_new_cb().
+ */
+void ssl_sock_srv_try_reuse_sess(struct ssl_sock_ctx *ctx, struct server *srv)
+{
+       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
+                * it to ctx->ssl. Its refcount will be updated by the
+                * creation and by the assignment, so after assigning
+                * it or failing to, we must always free it to decrement
+                * the refcount.
+                */
+               const unsigned char *ptr = srv->ssl_ctx.reused_sess[tid].ptr;
+               SSL_SESSION *sess = d2i_SSL_SESSION(NULL, &ptr, srv->ssl_ctx.reused_sess[tid].size);
+
+               if (sess && !SSL_set_session(ctx->ssl, sess)) {
+                       uint old_tid = HA_ATOMIC_LOAD(&srv->ssl_ctx.last_ssl_sess_tid); // 0=none, >0 = tid + 1
+                       if (old_tid == tid + 1)
+                               HA_ATOMIC_CAS(&srv->ssl_ctx.last_ssl_sess_tid, &old_tid, 0); // no more valid
+                       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);
+                       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);
+                       HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[tid].sess_lock);
+               } else if (sess) {
+                       /* already assigned, not needed anymore */
+                       SSL_SESSION_free(sess);
+                       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);
+                       HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[tid].sess_lock);
+               }
+       } else {
+               /* No session available yet, let's see if we can pick one
+                * from another thread. If old_tid is non-null, it designates
+                * the index of a recently updated thread that might still have
+                * a usable session. All threads are collectively responsible
+                * for resetting the index if it fails.
+                */
+               const unsigned char *ptr;
+               SSL_SESSION *sess;
+               uint old_tid = HA_ATOMIC_LOAD(&srv->ssl_ctx.last_ssl_sess_tid); // 0=none, >0 = tid + 1
+
+               if (old_tid) {
+                       HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[old_tid-1].sess_lock);
+
+                       ptr = srv->ssl_ctx.reused_sess[old_tid-1].ptr;
+                       if (ptr) {
+                               sess = d2i_SSL_SESSION(NULL, &ptr, srv->ssl_ctx.reused_sess[old_tid-1].size);
+                               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
+                                       SSL_SESSION_free(sess);
+                               }
+                       }
+
+                       if (srv->ssl_ctx.reused_sess[old_tid-1].sni)
+                               SSL_set_tlsext_host_name(ctx->ssl, srv->ssl_ctx.reused_sess[old_tid-1].sni);
+
+                       HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[old_tid-1].sess_lock);
+               }
+       }
+       HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.lock);
+}
+
 /*
  * This function is called if SSL * context is not yet allocated. The function
  * is designed to be called before any other data-layer operation and sets the
@@ -5136,69 +5205,7 @@ static int ssl_sock_init(struct connection *conn, void **xprt_ctx)
                if (srv->ssl_ctx.renegotiate == SSL_RENEGOTIATE_ON)
                        SSL_set_renegotiate_mode(ctx->ssl, ssl_renegotiate_freely);
 #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
-                        * it to ctx->ssl. Its refcount will be updated by the
-                        * creation and by the assignment, so after assigning
-                        * it or failing to, we must always free it to decrement
-                        * the refcount.
-                        */
-                       const unsigned char *ptr = srv->ssl_ctx.reused_sess[tid].ptr;
-                       SSL_SESSION *sess = d2i_SSL_SESSION(NULL, &ptr, srv->ssl_ctx.reused_sess[tid].size);
-
-                       if (sess && !SSL_set_session(ctx->ssl, sess)) {
-                               uint old_tid = HA_ATOMIC_LOAD(&srv->ssl_ctx.last_ssl_sess_tid); // 0=none, >0 = tid + 1
-                               if (old_tid == tid + 1)
-                                       HA_ATOMIC_CAS(&srv->ssl_ctx.last_ssl_sess_tid, &old_tid, 0); // no more valid
-                               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);
-                               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);
-                               HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[tid].sess_lock);
-                       } else if (sess) {
-                               /* already assigned, not needed anymore */
-                               SSL_SESSION_free(sess);
-                               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);
-                               HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[tid].sess_lock);
-                       }
-               } else {
-                       /* No session available yet, let's see if we can pick one
-                        * from another thread. If old_tid is non-null, it designates
-                        * the index of a recently updated thread that might still have
-                        * a usable session. All threads are collectively responsible
-                        * for resetting the index if it fails.
-                        */
-                       const unsigned char *ptr;
-                       SSL_SESSION *sess;
-                       uint old_tid = HA_ATOMIC_LOAD(&srv->ssl_ctx.last_ssl_sess_tid); // 0=none, >0 = tid + 1
-
-                       if (old_tid) {
-                               HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[old_tid-1].sess_lock);
-
-                               ptr = srv->ssl_ctx.reused_sess[old_tid-1].ptr;
-                               if (ptr) {
-                                       sess = d2i_SSL_SESSION(NULL, &ptr, srv->ssl_ctx.reused_sess[old_tid-1].size);
-                                       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
-                                               SSL_SESSION_free(sess);
-                                       }
-                               }
-
-                               if (srv->ssl_ctx.reused_sess[old_tid-1].sni)
-                                       SSL_set_tlsext_host_name(ctx->ssl, srv->ssl_ctx.reused_sess[old_tid-1].sni);
-
-                               HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.reused_sess[old_tid-1].sess_lock);
-                       }
-               }
-               HA_RWLOCK_RDUNLOCK(SSL_SERVER_LOCK, &srv->ssl_ctx.lock);
-
+               ssl_sock_srv_try_reuse_sess(ctx, srv);
                /* leave init state and start handshake */
                conn->flags |= CO_FL_SSL_WAIT_HS | CO_FL_WAIT_L6_CONN;