mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 07:07:04 +02:00
MEDIUM: ssl: Add 'tune.ssl.ocsp-update.mode' global option
This option can be used to set a default ocsp-update mode for all certificates of a given conf file. It allows to activate ocsp-update on certificates without the need to create separate crt-lists. It can still be superseded by the crt-list 'ocsp-update' option. It takes either "on" or "off" as value and defaults to "off". Since setting this new parameter to "on" would mean that we try to enable ocsp-update on any certificate, and also certificates that don't have an OCSP URI, the checks performed in ssl_sock_load_ocsp were softened. We don't systematically raise an error when trying to enable ocsp-update on a certificate that does not have an OCSP URI, be it via the global option or the crt-list one. We will still raise an error when a user tries to load a certificate that does have an OCSP URI but a missing issuer certificate (if ocsp-update is enabled).
This commit is contained in:
parent
b1d623949c
commit
7359c0c7f4
@ -3959,6 +3959,15 @@ tune.ssl.ocsp-update.mindelay <number>
|
||||
"tune.ssl.ocsp-update.maxdelay". See option "ocsp-update" for more
|
||||
information about the auto update mechanism.
|
||||
|
||||
tune.ssl.ocsp-update.mode [ on | off ]
|
||||
Sets the default ocsp-update mode for all certificates used in the
|
||||
configuration. This global option can be superseded by the crt-list
|
||||
"ocsp-update" option but an error will be raised if a given certificate has
|
||||
two distinct configurations simultaneously. This option is set to "off" by
|
||||
default.
|
||||
See option "ocsp-update" for more information about the auto update
|
||||
mechanism.
|
||||
|
||||
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
|
||||
@ -16047,11 +16056,15 @@ ocsp-update [ off | on ] (crt-list only)
|
||||
Its value defaults to 'off'.
|
||||
Please note that for now, this option can only be used in a crt-list line, it
|
||||
cannot be used directly on a bind line. It lies in this "Bind options"
|
||||
section because it is still a frontend option. This limitation was set so
|
||||
that the option applies to only one certificate at a time.
|
||||
section because it is still a frontend option. For now, the only way to
|
||||
enable OCSP auto update on a bind line certificate is via the global option
|
||||
"tune.ocsp-update.mode".
|
||||
If a given certificate is used in multiple crt-lists with different values of
|
||||
the 'ocsp-update' set, an error will be raised. Here is an example
|
||||
configuration enabling it:
|
||||
the 'ocsp-update' set, an error will be raised. Likewise, if a certificate
|
||||
inherits from the global option on a bind line and has an incompatible
|
||||
explicit 'ocsp-update' option set in a crt-list, the same error will be
|
||||
raised.
|
||||
Here is an example configuration enabling it:
|
||||
|
||||
haproxy.cfg:
|
||||
frontend fe
|
||||
@ -16069,12 +16082,12 @@ ocsp-update [ off | on ] (crt-list only)
|
||||
hour limit. A minimum update interval of 5 minutes will still exist in order
|
||||
to avoid updating too often responses that have a really short expire time or
|
||||
even no 'Next Update' at all. Because of this hard limit, please note that
|
||||
when auto update is set to 'on' or 'auto', any OCSP response loaded during
|
||||
init will not be updated until at least 5 minutes, even if its expire time
|
||||
ends before now+5m. This should not be too much of a hassle since an OCSP
|
||||
response must be valid when it gets loaded during init (its expire time must
|
||||
be in the future) so it is unlikely that this response expires in such a
|
||||
short time after init.
|
||||
when auto update is set to 'on', any OCSP response loaded during init will
|
||||
not be updated until at least 5 minutes, even if its expire time ends before
|
||||
now+5m. This should not be too much of a hassle since an OCSP response must
|
||||
be valid when it gets loaded during init (its expire time must be in the
|
||||
future) so it is unlikely that this response expires in such a 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.
|
||||
|
@ -309,6 +309,7 @@ struct global_ssl {
|
||||
struct {
|
||||
unsigned int delay_max;
|
||||
unsigned int delay_min;
|
||||
int mode; /* default mode used for ocsp auto-update (off, on) */
|
||||
} ocsp_update;
|
||||
#endif
|
||||
};
|
||||
|
@ -2222,6 +2222,35 @@ static int ssl_parse_global_ocsp_mindelay(char **args, int section_type, struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ssl_parse_global_ocsp_update_mode(char **args, int section_type, struct proxy *curpx,
|
||||
const struct proxy *defpx, const char *file, int line,
|
||||
char **err)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!*args[1]) {
|
||||
memprintf(err, "'%s' : expecting <on|off>", args[0]);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
if (strcmp(args[1], "on") == 0)
|
||||
global_ssl.ocsp_update.mode = SSL_SOCK_OCSP_UPDATE_ON;
|
||||
else if (strcmp(args[1], "off") == 0)
|
||||
global_ssl.ocsp_update.mode = SSL_SOCK_OCSP_UPDATE_OFF;
|
||||
else {
|
||||
memprintf(err, "'%s' : expecting <on|off>", args[0]);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
if (global_ssl.ocsp_update.mode != SSL_SOCK_OCSP_UPDATE_OFF) {
|
||||
/* We might need to create the main ocsp update task */
|
||||
ret = ssl_create_ocsp_update_task(err);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Note: must not be declared <const> as its list will be overwritten.
|
||||
@ -2411,6 +2440,7 @@ static struct cfg_kw_list cfg_kws = {ILH, {
|
||||
#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 },
|
||||
{ CFG_GLOBAL, "tune.ssl.ocsp-update.mode", ssl_parse_global_ocsp_update_mode },
|
||||
#endif
|
||||
{ 0, NULL, NULL },
|
||||
}};
|
||||
|
@ -355,6 +355,8 @@ int ssl_sock_load_files_into_ckch(const char *path, struct ckch_data *data, char
|
||||
goto end;
|
||||
}
|
||||
|
||||
data->ocsp_update_mode = global_ssl.ocsp_update.mode;
|
||||
|
||||
/* remove the ".crt" extension */
|
||||
if (global_ssl.extra_files_noext) {
|
||||
char *ext;
|
||||
|
@ -600,6 +600,8 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
|
||||
entry->crtlist = newlist;
|
||||
if (entry->ssl_conf)
|
||||
ckchs->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
|
||||
if (ckchs->data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_DFLT)
|
||||
ckchs->data->ocsp_update_mode = global_ssl.ocsp_update.mode;
|
||||
ebpt_insert(&newlist->entries, &entry->node);
|
||||
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
|
||||
LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
|
||||
@ -655,6 +657,8 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
|
||||
|
||||
if (entry->ssl_conf)
|
||||
ckchs->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
|
||||
if (ckchs->data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_DFLT)
|
||||
ckchs->data->ocsp_update_mode = global_ssl.ocsp_update.mode;
|
||||
ebpt_insert(&newlist->entries, &entry_dup->node);
|
||||
LIST_APPEND(&newlist->ord_entries, &entry_dup->by_crtlist);
|
||||
LIST_APPEND(&ckchs->crtlist_entry, &entry_dup->by_ckch_store);
|
||||
@ -685,6 +689,8 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
|
||||
|
||||
if (entry->ssl_conf)
|
||||
ckchs->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
|
||||
if (ckchs->data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_DFLT)
|
||||
ckchs->data->ocsp_update_mode = global_ssl.ocsp_update.mode;
|
||||
ebpt_insert(&newlist->entries, &entry->node);
|
||||
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
|
||||
LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
|
||||
@ -1364,6 +1370,8 @@ static int cli_parse_add_crtlist(char **args, char *payload, struct appctx *appc
|
||||
|
||||
if (entry->ssl_conf)
|
||||
store->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
|
||||
if (store->data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_DFLT)
|
||||
store->data->ocsp_update_mode = global_ssl.ocsp_update.mode;
|
||||
|
||||
/* check if it's possible to insert this new crtlist_entry */
|
||||
entry->node.key = store;
|
||||
|
@ -1720,19 +1720,36 @@ static void cli_release_show_ocspresponse(struct appctx *appctx)
|
||||
ssl_sock_free_ocsp_instance(ctx->ocsp);
|
||||
}
|
||||
|
||||
/* Check if the ckch_store and the entry does have the same configuration */
|
||||
/* Check if the ckch_store and the entry do have the same configuration. Also
|
||||
* ensure that those options are compatible with the global ocsp-update mode. */
|
||||
int ocsp_update_check_cfg_consistency(struct ckch_store *store, struct crtlist_entry *entry, char *crt_path, char **err)
|
||||
{
|
||||
int err_code = ERR_NONE;
|
||||
int incompat_found = 0;
|
||||
|
||||
if (store->data->ocsp_update_mode != SSL_SOCK_OCSP_UPDATE_DFLT || entry->ssl_conf) {
|
||||
if ((!entry->ssl_conf && store->data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON)
|
||||
|| (entry->ssl_conf && entry->ssl_conf->ocsp_update != SSL_SOCK_OCSP_UPDATE_OFF &&
|
||||
store->data->ocsp_update_mode != entry->ssl_conf->ocsp_update)) {
|
||||
memprintf(err, "%sIncompatibilities found in OCSP update mode for certificate %s\n", err && *err ? *err : "", crt_path);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
switch(store->data->ocsp_update_mode) {
|
||||
case SSL_SOCK_OCSP_UPDATE_DFLT:
|
||||
if (entry && entry->ssl_conf && entry->ssl_conf->ocsp_update == SSL_SOCK_OCSP_UPDATE_ON &&
|
||||
global_ssl.ocsp_update.mode != SSL_SOCK_OCSP_UPDATE_ON)
|
||||
incompat_found = 1;
|
||||
break;
|
||||
case SSL_SOCK_OCSP_UPDATE_OFF:
|
||||
if ((entry && entry->ssl_conf && entry->ssl_conf->ocsp_update == SSL_SOCK_OCSP_UPDATE_ON) ||
|
||||
((!entry || !entry->ssl_conf) && global_ssl.ocsp_update.mode == SSL_SOCK_OCSP_UPDATE_ON))
|
||||
incompat_found = 1;
|
||||
break;
|
||||
case SSL_SOCK_OCSP_UPDATE_ON:
|
||||
if ((entry && entry->ssl_conf && entry->ssl_conf->ocsp_update != SSL_SOCK_OCSP_UPDATE_ON) ||
|
||||
((!entry || !entry->ssl_conf) && global_ssl.ocsp_update.mode != SSL_SOCK_OCSP_UPDATE_ON))
|
||||
incompat_found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (incompat_found) {
|
||||
memprintf(err, "%sIncompatibilities found in OCSP update mode for certificate %s\n", err && *err ? *err : "", crt_path);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
|
@ -140,6 +140,7 @@ struct global_ssl global_ssl = {
|
||||
#ifndef OPENSSL_NO_OCSP
|
||||
.ocsp_update.delay_max = SSL_OCSP_UPDATE_DELAY_MAX,
|
||||
.ocsp_update.delay_min = SSL_OCSP_UPDATE_DELAY_MIN,
|
||||
.ocsp_update.mode = SSL_SOCK_OCSP_UPDATE_DFLT,
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -1125,24 +1126,28 @@ static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_data *
|
||||
char *err = NULL;
|
||||
size_t path_len;
|
||||
int inc_refcount_store = 0;
|
||||
int enable_auto_update = (data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON ||
|
||||
(data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_DFLT &&
|
||||
global_ssl.ocsp_update.mode == SSL_SOCK_OCSP_UPDATE_ON));
|
||||
|
||||
x = data->cert;
|
||||
if (!x)
|
||||
goto out;
|
||||
|
||||
ssl_ocsp_get_uri_from_cert(x, ocsp_uri, &err);
|
||||
/* We should have an "OCSP URI" field in order for auto update to work. */
|
||||
if (data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON && b_data(ocsp_uri) == 0)
|
||||
goto out;
|
||||
|
||||
/* In case of ocsp update mode set to 'on', this function might be
|
||||
* called with no known ocsp response. If no ocsp uri can be found in
|
||||
* the certificate, nothing needs to be done here. */
|
||||
if (!data->ocsp_response && !data->ocsp_cid) {
|
||||
if (data->ocsp_update_mode != SSL_SOCK_OCSP_UPDATE_ON || b_data(ocsp_uri) == 0) {
|
||||
/* In case of ocsp update mode set to 'on', this function might
|
||||
* be called with no known ocsp response. If no ocsp uri can be
|
||||
* found in the certificate, nothing needs to be done here. */
|
||||
if (!enable_auto_update || b_data(ocsp_uri) == 0) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* If we have an OCSP response provided and the ocsp auto update
|
||||
* enabled, we must raise an error if no OCSP URI was found. */
|
||||
if (data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON && b_data(ocsp_uri) == 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
issuer = data->ocsp_issuer;
|
||||
@ -1284,7 +1289,7 @@ static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_data *
|
||||
*/
|
||||
memcpy(iocsp->path, path, path_len + 1);
|
||||
|
||||
if (data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON) {
|
||||
if (enable_auto_update) {
|
||||
ssl_ocsp_update_insert(iocsp);
|
||||
/* If we are during init the update task is not
|
||||
* scheduled yet so a wakeup won't do anything.
|
||||
@ -1296,7 +1301,7 @@ static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_data *
|
||||
if (ocsp_update_task)
|
||||
task_wakeup(ocsp_update_task, TASK_WOKEN_MSG);
|
||||
}
|
||||
} else if (iocsp->uri && data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON) {
|
||||
} else if (iocsp->uri && enable_auto_update) {
|
||||
/* This unlikely case can happen if a series of "del ssl
|
||||
* crt-list" / "add ssl crt-list" commands are made on the CLI.
|
||||
* In such a case, the OCSP response tree entry will be created
|
||||
@ -3843,12 +3848,11 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, int is_default,
|
||||
/* we found the ckchs in the tree, we can use it directly */
|
||||
cfgerr |= ssl_sock_load_ckchs(path, ckchs, bind_conf, NULL, NULL, 0, is_default, &ckch_inst, err);
|
||||
|
||||
/* This certificate has an 'ocsp-update' already set in a
|
||||
* previous crt-list so we must raise an error. */
|
||||
if (ckchs->data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON) {
|
||||
memprintf(err, "%sIncompatibilities found in OCSP update mode for certificate %s\n", err && *err ? *err: "", path);
|
||||
cfgerr |= ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
/* The ckch_store might have been created through a crt-list
|
||||
* line so we must check that the ocsp-update modes are still
|
||||
* compatible between the global mode and the explicit one from
|
||||
* the crt-list. */
|
||||
cfgerr |= ocsp_update_check_cfg_consistency(ckchs, NULL, path, err);
|
||||
|
||||
found++;
|
||||
} else if (stat(path, &buf) == 0) {
|
||||
|
Loading…
Reference in New Issue
Block a user