mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 23:27: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
|
"tune.ssl.ocsp-update.maxdelay". See option "ocsp-update" for more
|
||||||
information about the auto update mechanism.
|
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>
|
tune.stick-counters <number>
|
||||||
Sets the number of stick-counters that may be tracked at the same time by a
|
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
|
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'.
|
Its value defaults to 'off'.
|
||||||
Please note that for now, this option can only be used in a crt-list line, it
|
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"
|
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
|
section because it is still a frontend option. For now, the only way to
|
||||||
that the option applies to only one certificate at a time.
|
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
|
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
|
the 'ocsp-update' set, an error will be raised. Likewise, if a certificate
|
||||||
configuration enabling it:
|
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:
|
haproxy.cfg:
|
||||||
frontend fe
|
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
|
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
|
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
|
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
|
when auto update is set to 'on', any OCSP response loaded during init will
|
||||||
init will not be updated until at least 5 minutes, even if its expire time
|
not be updated until at least 5 minutes, even if its expire time ends before
|
||||||
ends before now+5m. This should not be too much of a hassle since an OCSP
|
now+5m. This should not be too much of a hassle since an OCSP response must
|
||||||
response must be valid when it gets loaded during init (its expire time must
|
be valid when it gets loaded during init (its expire time must be in the
|
||||||
be in the future) so it is unlikely that this response expires in such a
|
future) so it is unlikely that this response expires in such a short time
|
||||||
short time after init.
|
after init.
|
||||||
On the other hand, if a certificate has an OCSP uri specified and no OCSP
|
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
|
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.
|
||||||
|
@ -309,6 +309,7 @@ struct global_ssl {
|
|||||||
struct {
|
struct {
|
||||||
unsigned int delay_max;
|
unsigned int delay_max;
|
||||||
unsigned int delay_min;
|
unsigned int delay_min;
|
||||||
|
int mode; /* default mode used for ocsp auto-update (off, on) */
|
||||||
} ocsp_update;
|
} ocsp_update;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -2222,6 +2222,35 @@ static int ssl_parse_global_ocsp_mindelay(char **args, int section_type, struct
|
|||||||
return 0;
|
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.
|
/* 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
|
#ifndef OPENSSL_NO_OCSP
|
||||||
{ CFG_GLOBAL, "tune.ssl.ocsp-update.maxdelay", ssl_parse_global_ocsp_maxdelay },
|
{ 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.mindelay", ssl_parse_global_ocsp_mindelay },
|
||||||
|
{ CFG_GLOBAL, "tune.ssl.ocsp-update.mode", ssl_parse_global_ocsp_update_mode },
|
||||||
#endif
|
#endif
|
||||||
{ 0, NULL, NULL },
|
{ 0, NULL, NULL },
|
||||||
}};
|
}};
|
||||||
|
@ -355,6 +355,8 @@ int ssl_sock_load_files_into_ckch(const char *path, struct ckch_data *data, char
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->ocsp_update_mode = global_ssl.ocsp_update.mode;
|
||||||
|
|
||||||
/* remove the ".crt" extension */
|
/* remove the ".crt" extension */
|
||||||
if (global_ssl.extra_files_noext) {
|
if (global_ssl.extra_files_noext) {
|
||||||
char *ext;
|
char *ext;
|
||||||
|
@ -600,6 +600,8 @@ int crtlist_parse_file(char *file, struct bind_conf *bind_conf, struct proxy *cu
|
|||||||
entry->crtlist = newlist;
|
entry->crtlist = newlist;
|
||||||
if (entry->ssl_conf)
|
if (entry->ssl_conf)
|
||||||
ckchs->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
|
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);
|
ebpt_insert(&newlist->entries, &entry->node);
|
||||||
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
|
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
|
||||||
LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
|
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)
|
if (entry->ssl_conf)
|
||||||
ckchs->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
|
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);
|
ebpt_insert(&newlist->entries, &entry_dup->node);
|
||||||
LIST_APPEND(&newlist->ord_entries, &entry_dup->by_crtlist);
|
LIST_APPEND(&newlist->ord_entries, &entry_dup->by_crtlist);
|
||||||
LIST_APPEND(&ckchs->crtlist_entry, &entry_dup->by_ckch_store);
|
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)
|
if (entry->ssl_conf)
|
||||||
ckchs->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
|
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);
|
ebpt_insert(&newlist->entries, &entry->node);
|
||||||
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
|
LIST_APPEND(&newlist->ord_entries, &entry->by_crtlist);
|
||||||
LIST_APPEND(&ckchs->crtlist_entry, &entry->by_ckch_store);
|
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)
|
if (entry->ssl_conf)
|
||||||
store->data->ocsp_update_mode = entry->ssl_conf->ocsp_update;
|
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 */
|
/* check if it's possible to insert this new crtlist_entry */
|
||||||
entry->node.key = store;
|
entry->node.key = store;
|
||||||
|
@ -1720,19 +1720,36 @@ static void cli_release_show_ocspresponse(struct appctx *appctx)
|
|||||||
ssl_sock_free_ocsp_instance(ctx->ocsp);
|
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 ocsp_update_check_cfg_consistency(struct ckch_store *store, struct crtlist_entry *entry, char *crt_path, char **err)
|
||||||
{
|
{
|
||||||
int err_code = ERR_NONE;
|
int err_code = ERR_NONE;
|
||||||
|
int incompat_found = 0;
|
||||||
|
|
||||||
if (store->data->ocsp_update_mode != SSL_SOCK_OCSP_UPDATE_DFLT || entry->ssl_conf) {
|
switch(store->data->ocsp_update_mode) {
|
||||||
if ((!entry->ssl_conf && store->data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON)
|
case SSL_SOCK_OCSP_UPDATE_DFLT:
|
||||||
|| (entry->ssl_conf && entry->ssl_conf->ocsp_update != SSL_SOCK_OCSP_UPDATE_OFF &&
|
if (entry && entry->ssl_conf && entry->ssl_conf->ocsp_update == SSL_SOCK_OCSP_UPDATE_ON &&
|
||||||
store->data->ocsp_update_mode != entry->ssl_conf->ocsp_update)) {
|
global_ssl.ocsp_update.mode != SSL_SOCK_OCSP_UPDATE_ON)
|
||||||
memprintf(err, "%sIncompatibilities found in OCSP update mode for certificate %s\n", err && *err ? *err : "", crt_path);
|
incompat_found = 1;
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
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;
|
return err_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +140,7 @@ struct global_ssl global_ssl = {
|
|||||||
#ifndef OPENSSL_NO_OCSP
|
#ifndef OPENSSL_NO_OCSP
|
||||||
.ocsp_update.delay_max = SSL_OCSP_UPDATE_DELAY_MAX,
|
.ocsp_update.delay_max = SSL_OCSP_UPDATE_DELAY_MAX,
|
||||||
.ocsp_update.delay_min = SSL_OCSP_UPDATE_DELAY_MIN,
|
.ocsp_update.delay_min = SSL_OCSP_UPDATE_DELAY_MIN,
|
||||||
|
.ocsp_update.mode = SSL_SOCK_OCSP_UPDATE_DFLT,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1125,24 +1126,28 @@ static int ssl_sock_load_ocsp(const char *path, SSL_CTX *ctx, struct ckch_data *
|
|||||||
char *err = NULL;
|
char *err = NULL;
|
||||||
size_t path_len;
|
size_t path_len;
|
||||||
int inc_refcount_store = 0;
|
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;
|
x = data->cert;
|
||||||
if (!x)
|
if (!x)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ssl_ocsp_get_uri_from_cert(x, ocsp_uri, &err);
|
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_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;
|
ret = 0;
|
||||||
goto out;
|
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;
|
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);
|
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);
|
ssl_ocsp_update_insert(iocsp);
|
||||||
/* If we are during init the update task is not
|
/* If we are during init the update task is not
|
||||||
* scheduled yet so a wakeup won't do anything.
|
* 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)
|
if (ocsp_update_task)
|
||||||
task_wakeup(ocsp_update_task, TASK_WOKEN_MSG);
|
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
|
/* This unlikely case can happen if a series of "del ssl
|
||||||
* crt-list" / "add ssl crt-list" commands are made on the CLI.
|
* crt-list" / "add ssl crt-list" commands are made on the CLI.
|
||||||
* In such a case, the OCSP response tree entry will be created
|
* 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 */
|
/* 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);
|
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
|
/* The ckch_store might have been created through a crt-list
|
||||||
* previous crt-list so we must raise an error. */
|
* line so we must check that the ocsp-update modes are still
|
||||||
if (ckchs->data->ocsp_update_mode == SSL_SOCK_OCSP_UPDATE_ON) {
|
* compatible between the global mode and the explicit one from
|
||||||
memprintf(err, "%sIncompatibilities found in OCSP update mode for certificate %s\n", err && *err ? *err: "", path);
|
* the crt-list. */
|
||||||
cfgerr |= ERR_ALERT | ERR_FATAL;
|
cfgerr |= ocsp_update_check_cfg_consistency(ckchs, NULL, path, err);
|
||||||
}
|
|
||||||
|
|
||||||
found++;
|
found++;
|
||||||
} else if (stat(path, &buf) == 0) {
|
} else if (stat(path, &buf) == 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user