]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: ssl: release the previous client cert reference at depth > 0
authorRemi Tricot-Le Breton <rlebreton@haproxy.com>
Thu, 6 Aug 2026 07:36:48 +0000 (09:36 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 17 Aug 2026 17:11:33 +0000 (19:11 +0200)
The verify callback stores a reference to the client's certificate so that
it can still be reported in logs when the verification fails. At depth 0
it correctly releases the reference that may have been stored by an
earlier call before replacing it, but the depth > 0 branch, which does the
same for chain certificates, overwrote the stored pointer without
releasing it first.

For deployments using "ca-ignore-err", a client presenting a chain that
triggers more than one ignored CA-level error therefore leaks one X509
object per extra error, on every single handshake. Since the client fully
controls the chain it presents and the rate at which it connects, memory
grows without bound until the process is killed.

Let's free the previous reference in that branch too, as the depth 0
branch does.

This was introduced in 2.5 by commit 74f6ab6e8 ("MEDIUM: ssl: Keep a
reference to the client's certificate for use in logs"). It must be
backported to all stable versions.

Reported-by: Claude (ANT-2026-6WW7AT7V)
src/ssl_sock.c

index eb6ca6cb9bf925ea425751317e70137db90d8c43..4fcf0ab67121f689beb1f06ce97b710200486b2e 100644 (file)
@@ -1816,9 +1816,15 @@ int ssl_sock_bind_verifycbk(int ok, X509_STORE_CTX *x_store)
                 * reference right now. */
                certs = X509_STORE_CTX_get1_chain(x_store);
                if (certs) {
+                       X509 *prev_crt = client_crt;
+
                        client_crt = sk_X509_value(certs, 0);
                        if (client_crt) {
                                X509_up_ref(client_crt);
+                               /* release the reference possibly stored by a
+                                * previous call at another depth.
+                                */
+                               X509_free(prev_crt);
                                SSL_set_ex_data(ssl, ssl_client_crt_ref_index, client_crt);
                        }
                        sk_X509_pop_free(certs, X509_free);