]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: allow to disable certificate compression 20260127-openssl-compression flx05/20260127-openssl-compression
authorWilliam Lallemand <wlallemand@haproxy.com>
Tue, 27 Jan 2026 11:25:25 +0000 (12:25 +0100)
committerWilliam Lallemand <wlallemand@haproxy.com>
Tue, 27 Jan 2026 15:10:41 +0000 (16:10 +0100)
This option allows to disable the certificate compression (RFC 8879)
using OpenSSL >= 3.2.0.

This feature is known to permit some denial of services by causing extra
memory allocations of approximately 22MiB and extra CPU work per
connection with OpenSSL versions affected by CVE-2025-66199.
( https://openssl-library.org/news/vulnerabilities/index.html#CVE-2025-66199 )

Setting this to "off" permits to mitigate the problem.

Must be backported to every stable branches.

doc/configuration.txt
include/haproxy/ssl_sock-t.h
src/cfgparse-ssl.c
src/ssl_sock.c

index 989290601f07a1c17faffad4f585ec57b21b89c6..8c798c06fcbfa0d51bd0ccc1267342f87b9c499f 100644 (file)
@@ -1983,6 +1983,7 @@ The following keywords are supported in the "global" section :
    - tune.ssl.cachesize
    - tune.ssl.capture-buffer-size
    - tune.ssl.capture-cipherlist-size (deprecated)
+   - tune.ssl.certificate-compression
    - tune.ssl.default-dh-param
    - tune.ssl.force-private-cache
    - tune.ssl.hard-maxrecord
@@ -5310,6 +5311,22 @@ tune.ssl.capture-cipherlist-size <number> (deprecated)
   formats. If the value is 0 (default value) the capture is disabled,
   otherwise a buffer is allocated for each SSL/TLS connection.
 
+tune.ssl.certificate-compression { auto | off }
+  This setting allows to configure the certificate compression support which is
+  an extension (RFC 8879) to TLS 1.3.
+
+  When set to "auto" it uses the default value of the TLS library.
+
+  With "off" it tries to explicitely disable the support of the feature.
+  HAProxy won't try to send compressed certificates anymore nor accept
+  compressed certificates.
+
+  Configures both backend and frontend sides.
+
+  This keyword is supported by OpenSSL >= 3.2.0.
+
+  The default value is auto.
+
 tune.ssl.default-dh-param <number>
   Sets the maximum size of the Diffie-Hellman parameters used for generating
   the ephemeral/temporary Diffie-Hellman key in case of DHE key exchange. The
index b1d660f3042093cae80c5a5a35619f6d41c33244..af10facee8deffe389cbed2da051c2cd91421d42 100644 (file)
@@ -338,6 +338,8 @@ struct global_ssl {
        int renegotiate; /* Renegotiate mode (SSL_RENEGOTIATE_ flag) */
        char **passphrase_cmd;
        int passphrase_cmd_args_cnt;
+
+       unsigned int certificate_compression:1; /* allow to explicitely disable certificate compression */
 };
 
 /* The order here matters for picking a default context,
index e5e539c082ebaad7a4dc08a5fedd7dd6dac3b619..3fa93966e4aa16cd12afbf409b2df87ddd6558f2 100644 (file)
@@ -496,6 +496,36 @@ static int ssl_parse_global_keylog(char **args, int section_type, struct proxy *
 }
 #endif
 
+/* Allow to explicitely disable certificate compression when set to "off" */
+#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
+static int ssl_parse_certificate_compression(char **args, int section_type, struct proxy *curpx,
+                                             const struct proxy *defpx, const char *file, int line,
+                                             char **err)
+{
+       if (too_many_args(1, args, err, NULL))
+               return -1;
+
+       if (strcmp(args[1], "auto") == 0)
+               global_ssl.certificate_compression = 1;
+       else if (strcmp(args[1], "off") == 0)
+               global_ssl.certificate_compression = 0;
+       else {
+               memprintf(err, "'%s' expects either 'on' or 'off' but got '%s'.", args[0], args[1]); return -1;
+       }
+
+       return 0;
+}
+#else
+static int ssl_parse_certificate_compression(char **args, int section_type, struct proxy *curpx,
+                                             const struct proxy *defpx, const char *file, int line,
+                                             char **err)
+{
+       memprintf(err, "'%s' is not supported by your TLS library. "
+                           "It is known to work only with OpenSSL >= 3.2.0.", args[0]);
+       return -1;
+}
+#endif
+
 /* parse "ssl.force-private-cache".
  * Returns <0 on alert, >0 on warning, 0 on success.
  */
@@ -2759,6 +2789,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
        { CFG_GLOBAL, "ssl-security-level", ssl_parse_security_level },
        { CFG_GLOBAL, "ssl-skip-self-issued-ca", ssl_parse_skip_self_issued_ca },
        { CFG_GLOBAL, "tune.ssl.cachesize", ssl_parse_global_int },
+       { CFG_GLOBAL, "tune.ssl.certificate-compression", ssl_parse_certificate_compression },
        { CFG_GLOBAL, "tune.ssl.default-dh-param", ssl_parse_global_default_dh },
        { CFG_GLOBAL, "tune.ssl.force-private-cache",  ssl_parse_global_private_cache },
        { CFG_GLOBAL, "tune.ssl.lifetime", ssl_parse_global_lifetime },
index 1fcec4ab4bf40420484505173bc774b651c99bce..27218e4a86544e3a76a1680ccb4eed8cef812310 100644 (file)
@@ -152,6 +152,9 @@ struct global_ssl global_ssl = {
 #endif
 #ifdef HAVE_ACME
        .acme_scheduler = 1,
+#endif
+#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
+       .certificate_compression = 1,
 #endif
        .renegotiate = SSL_RENEGOTIATE_DFLT,
        .passphrase_cmd = NULL,
@@ -4079,6 +4082,11 @@ ssl_sock_initial_ctx(struct bind_conf *bind_conf)
        options |= SSL_OP_NO_RENEGOTIATION;
 #endif
 
+#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
+       if (global_ssl.certificate_compression == 0)
+               options |= SSL_OP_NO_RX_CERTIFICATE_COMPRESSION | SSL_OP_NO_TX_CERTIFICATE_COMPRESSION;
+#endif
+
        SSL_CTX_set_options(ctx, options);
 
 #ifdef SSL_MODE_ASYNC
@@ -5132,6 +5140,11 @@ static int ssl_sock_prepare_srv_ssl_ctx(const struct server *srv, SSL_CTX *ctx)
                options &= ~SSL_OP_NO_RENEGOTIATION;
 #endif
 
+#ifdef SSL_OP_NO_RX_CERTIFICATE_COMPRESSION
+       if (global_ssl.certificate_compression == 0)
+               options |= SSL_OP_NO_RX_CERTIFICATE_COMPRESSION | SSL_OP_NO_TX_CERTIFICATE_COMPRESSION;
+#endif
+
        SSL_CTX_set_options(ctx, options);
 
 #ifdef SSL_MODE_ASYNC