]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: Add global options to modify ocsp update min/max delay
authorRemi Tricot-Le Breton <rlebreton@haproxy.com>
Tue, 28 Feb 2023 16:46:29 +0000 (17:46 +0100)
committerWilliam Lallemand <wlallemand@haproxy.org>
Thu, 2 Mar 2023 14:37:23 +0000 (15:37 +0100)
The minimum and maximum delays between two automatic updates of a given
OCSP response can now be set via global options. It allows to limit the
update rate of OCSP responses for configurations that use many frontend
certificates with the ocsp-update option set if the updates are deemed
too costly.

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

index 4538af74e575a1738b0270a5773fac27ab2ecdec..ae9c49e31507b989d1611ecd18014556aed1239a 100644 (file)
@@ -1188,6 +1188,8 @@ The following keywords are supported in the "global" section :
    - tune.ssl.lifetime
    - tune.ssl.maxrecord
    - tune.ssl.ssl-ctx-cache-size
+   - tune.ssl.ocsp-update.maxdelay
+   - tune.ssl.ocsp-update.mindelay
    - tune.vars.global-max-size
    - tune.vars.proc-max-size
    - tune.vars.reqres-max-size
@@ -3355,6 +3357,25 @@ tune.ssl.ssl-ctx-cache-size <number>
   dynamically is expensive, they are cached. The default cache size is set to
   1000 entries.
 
+tune.ssl.ocsp-update.maxdelay <number>
+  Sets the maximum interval between two automatic updates of the same OCSP
+  response. This time is expressed in seconds and defaults to 3600 (1 hour). It
+  must be set to a higher value than "tune.ssl.ocsp-update.mindelay". See
+  option "ocsp-update" for more information about the auto update mechanism.
+
+tune.ssl.ocsp-update.mindelay <number>
+  Sets the minimum interval between two automatic updates of the same OCSP
+  response. This time is expressed in seconds and defaults to 300 (5 minutes).
+  It is particularly useful for OCSP response that do not have explicit
+  expiration times. It must be set to a lower value than
+  "tune.ssl.ocsp-update.maxdelay". See option "ocsp-update" for more
+  information about the auto update mechanism.
+
+  Sets the size of the cache used to store generated certificates to <number>
+  entries. This is a LRU cache. Because generating a SSL certificate
+  dynamically is expensive, they are cached. The default cache size is set to
+  1000 entries.
+
 tune.stick-counters <number>
   Sets the number of stick-counters that may be tracked at the same time by a
   connection or a request via "track-sc*" actions in "tcp-request" or
@@ -14946,7 +14967,11 @@ ocsp-update [ off | on ]
   short time after init.
   On the other hand, if a certificate has an OCSP uri specified and no OCSP
   response, setting this option to 'on' for the given certificate will ensure
-  that the OCSP response gets fetched automatically right after init.
+  that the OCSP response gets fetched automatically right after init.  The
+  default minimum and maximum delays (5 minutes and 1 hour respectively) can be
+  configured by the "tune.ssl.ocsp-update.maxdelay" and
+  "tune.ssl.ocsp-update.mindelay" global options.
+
   Whenever an OCSP response is updated by the auto update task, a dedicated log
   line is emitted. It will follow a dedicated log-format that looks like the
   following "%ci:%cp [%tr] %ft %[ssl_ocsp_certid] %[ssl_ocsp_status]
index 44484319f7ba04828853b55af479fc1dd7ef8354..d78f941646f93357b81b42d395a1d461afe312d4 100644 (file)
 extern int ocsp_ex_index;
 #endif
 
+#define SSL_OCSP_UPDATE_DELAY_MAX 60*60 /* 1H */
+#define SSL_OCSP_UPDATE_DELAY_MIN 5*60  /* 5 minutes */
+#define SSL_OCSP_UPDATE_MARGIN 60   /* 1 minute */
+#define SSL_OCSP_HTTP_ERR_REPLAY 60 /* 1 minute */
+
 #if (defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP)
 /*
  * struct alignment works here such that the key.key is the same as key_data
index f7a96ba5cdfbe26d393b7533b60b2e06d011b65d..661c700271d85da0b68437189f8e9d3a31f6e666 100644 (file)
@@ -293,6 +293,13 @@ struct global_ssl {
        int keylog; /* activate keylog  */
        int extra_files; /* which files not defined in the configuration file are we looking for */
        int extra_files_noext; /* whether we remove the extension when looking up a extra file */
+
+#ifndef OPENSSL_NO_OCSP
+       struct {
+               unsigned int delay_max;
+               unsigned int delay_min;
+       } ocsp_update;
+#endif
 };
 
 /* The order here matters for picking a default context,
index 655115f52580d5bdd77d7c69dc1bdafffd404a4a..1b33eecb87ccc911c55da3521058c618ac4d73fd 100644 (file)
@@ -1906,6 +1906,59 @@ static int ssl_parse_skip_self_issued_ca(char **args, int section_type, struct p
 }
 
 
+static int ssl_parse_global_ocsp_maxdelay(char **args, int section_type, struct proxy *curpx,
+                                          const struct proxy *defpx, const char *file, int line,
+                                          char **err)
+{
+       int value = 0;
+
+       if (*(args[1]) == 0) {
+               memprintf(err, "'%s' expects an integer argument.", args[0]);
+               return -1;
+       }
+
+       value = atoi(args[1]);
+       if (value < 0) {
+               memprintf(err, "'%s' expects a positive numeric value.", args[0]);
+               return -1;
+       }
+
+       if (global_ssl.ocsp_update.delay_min > value) {
+               memprintf(err, "'%s' can not be lower than tune.ssl.ocsp-update.mindelay.", args[0]);
+               return -1;
+       }
+
+       global_ssl.ocsp_update.delay_max = value;
+
+       return 0;
+}
+
+static int ssl_parse_global_ocsp_mindelay(char **args, int section_type, struct proxy *curpx,
+                                          const struct proxy *defpx, const char *file, int line,
+                                          char **err)
+{
+       int value = 0;
+
+       if (*(args[1]) == 0) {
+               memprintf(err, "'%s' expects an integer argument.", args[0]);
+               return -1;
+       }
+
+       value = atoi(args[1]);
+       if (value < 0) {
+               memprintf(err, "'%s' expects a positive numeric value.", args[0]);
+               return -1;
+       }
+
+       if (value > global_ssl.ocsp_update.delay_max) {
+               memprintf(err, "'%s' can not be higher than tune.ssl.ocsp-update.maxdelay.", args[0]);
+               return -1;
+       }
+
+       global_ssl.ocsp_update.delay_min = value;
+
+       return 0;
+}
 
 
 
@@ -2081,6 +2134,10 @@ static struct cfg_kw_list cfg_kws = {ILH, {
 #endif
        { CFG_GLOBAL, "ssl-load-extra-files", ssl_parse_global_extra_files },
        { CFG_GLOBAL, "ssl-load-extra-del-ext", ssl_parse_global_extra_noext },
+#ifndef OPENSSL_NO_OCSP
+       { CFG_GLOBAL, "tune.ssl.ocsp-update.maxdelay", ssl_parse_global_ocsp_maxdelay },
+       { CFG_GLOBAL, "tune.ssl.ocsp-update.mindelay", ssl_parse_global_ocsp_mindelay },
+#endif
        { 0, NULL, NULL },
 }};
 
index db736fab3c88ea0d4a6072b59423363fb553dd3e..3cd35a5306cc568849c4101c4b8551401c31a012 100644 (file)
@@ -183,10 +183,6 @@ struct eb_root cert_ocsp_tree = EB_ROOT_UNIQUE;
 __decl_thread(HA_SPINLOCK_T ocsp_tree_lock);
 
 struct eb_root ocsp_update_tree = EB_ROOT; /* updatable ocsp responses sorted by next_update in absolute time */
-#define SSL_OCSP_UPDATE_DELAY_MAX 60*60 /* 1H */
-#define SSL_OCSP_UPDATE_DELAY_MIN 5*60  /* 5 minutes */
-#define SSL_OCSP_UPDATE_MARGIN 60   /* 1 minute */
-#define SSL_OCSP_HTTP_ERR_REPLAY 60 /* 1 minute */
 
 /* This function starts to check if the OCSP response (in DER format) contained
  * in chunk 'ocsp_response' is valid (else exits on error).
@@ -916,7 +912,7 @@ static inline void ssl_ocsp_set_next_update(struct certificate_ocsp *ocsp)
 {
        int update_margin = (ocsp->expire >= SSL_OCSP_UPDATE_MARGIN) ? SSL_OCSP_UPDATE_MARGIN : 0;
 
-       ocsp->next_update.key = MIN(now.tv_sec + SSL_OCSP_UPDATE_DELAY_MAX,
+       ocsp->next_update.key = MIN(now.tv_sec + global_ssl.ocsp_update.delay_max,
                                    ocsp->expire - update_margin);
 
        /* An already existing valid OCSP response that expires within less than
@@ -925,7 +921,7 @@ static inline void ssl_ocsp_set_next_update(struct certificate_ocsp *ocsp)
         * update of the same response. */
        if (b_data(&ocsp->response))
                ocsp->next_update.key = MAX(ocsp->next_update.key,
-                                           now.tv_sec + SSL_OCSP_UPDATE_DELAY_MIN);
+                                           now.tv_sec + global_ssl.ocsp_update.delay_min);
 }
 
 /*
@@ -980,7 +976,7 @@ int ssl_ocsp_update_insert_after_error(struct certificate_ocsp *ocsp)
         * being at most 1 hour (with the current default values).
         */
        replay_delay = MIN(SSL_OCSP_HTTP_ERR_REPLAY * (1 << ocsp->fail_count),
-                          SSL_OCSP_UPDATE_DELAY_MAX);
+                          global_ssl.ocsp_update.delay_max);
 
        if (ocsp->next_update.key < now.tv_sec + replay_delay)
                ocsp->next_update.key = now.tv_sec + replay_delay;
index 2d4ededf12d6eb91face6fe6f82a1c51026a32a8..1ce2483f3304d71e20ad582b892d6e446bb99b64 100644 (file)
@@ -132,7 +132,11 @@ struct global_ssl global_ssl = {
        .extra_files = SSL_GF_ALL,
        .extra_files_noext = 0,
 #ifdef HAVE_SSL_KEYLOG
-       .keylog = 0
+       .keylog = 0,
+#endif
+#ifndef OPENSSL_NO_OCSP
+       .ocsp_update.delay_max = SSL_OCSP_UPDATE_DELAY_MAX,
+       .ocsp_update.delay_min = SSL_OCSP_UPDATE_DELAY_MIN,
 #endif
 };