From bc31ef08964dad1a1de0d7c2c283861dcfdc167b Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 21 Aug 2023 11:17:10 +0200 Subject: [PATCH] DOC: ssl: add some comments about the non-obvious session allocation stuff The SSL session allocation/reuse part is far from being trivial, and there are some necessary tricks such as allocating then immediately freeing that are required by the API due to internal refcount. All of this is particularly hard to grasp, even with the scarce man pages. Let's document a little bit what's granted and expected along this path to help the reader later. --- src/ssl_sock.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 5c4f584ba1..141d8c9735 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -4273,6 +4273,7 @@ static int ssl_sess_new_srv_cb(SSL *ssl, SSL_SESSION *sess) unsigned char *ptr; const char *sni; + /* determine the required len to store this new session */ len = i2d_SSL_SESSION(sess, NULL); sni = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &s->ssl_ctx.lock); @@ -4286,9 +4287,13 @@ static int ssl_sess_new_srv_cb(SSL *ssl, SSL_SESSION *sess) s->ssl_ctx.reused_sess[tid].ptr = ptr; s->ssl_ctx.reused_sess[tid].allocated_size = len; } + if (s->ssl_ctx.reused_sess[tid].ptr) { - s->ssl_ctx.reused_sess[tid].size = i2d_SSL_SESSION(sess, - &ptr); + /* store the new session into ptr and advance it; save the + * resulting size. It's guaranteed to be equal to the returned + * len above, and the pointer to be advanced by as much. + */ + s->ssl_ctx.reused_sess[tid].size = i2d_SSL_SESSION(sess, &ptr); } if (s->ssl_ctx.reused_sess[tid].sni) { @@ -5703,12 +5708,19 @@ static int ssl_sock_init(struct connection *conn, void **xprt_ctx) SSL_set_connect_state(ctx->ssl); HA_RWLOCK_RDLOCK(SSL_SERVER_LOCK, &(__objt_server(conn->target)->ssl_ctx.lock)); if (__objt_server(conn->target)->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 = __objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr; SSL_SESSION *sess = d2i_SSL_SESSION(NULL, &ptr, __objt_server(conn->target)->ssl_ctx.reused_sess[tid].size); if (sess && !SSL_set_session(ctx->ssl, sess)) { SSL_SESSION_free(sess); ha_free(&__objt_server(conn->target)->ssl_ctx.reused_sess[tid].ptr); } else if (sess) { + /* already assigned, not needed anymore */ SSL_SESSION_free(sess); } } -- 2.47.3