MEDIUM: ssl: implements 'default-crt' keyword for bind Lines

The 'default-crt' bind keyword allows to specify multiples
default/fallback certificates, allowing one to have an RSA as well as an
ECDSA default.
This commit is contained in:
William Lallemand 2024-01-12 17:32:48 +01:00
parent 47bae78147
commit 97832ab823
4 changed files with 29 additions and 8 deletions

View File

@ -15474,11 +15474,12 @@ crt <cert>
This means that when loading certificates from a directory, it is highly
recommended to load the default one first as a file or to ensure that it will
always be the first one in the directory. In order to chose multiple default
certificates (1 rsa and 1 ecdsa), there are 2 options:
certificates (1 rsa and 1 ecdsa), there are 3 options:
- A multi-cert bundle can be configured as the first certificate
(`crt foobar.pem` in the configuration where the existing files
are `foobar.pem.ecdsa` and `foobar.pem.rsa`.
- Or a '*' filter for each certificate in a crt-list line.
- The 'default-crt' keyword can be used.
Note that the same cert may be loaded multiple times without side effects.
@ -15585,6 +15586,23 @@ crt-list <file>
default.pem.rsa *
default.pem.ecdsa *
default-crt <cert>
This option does the same as the "crt" option, with the difference that this
certificate will be used as a default one. It is possible to add multiple
default certificates to have an ECDSA and an RSA one, having more is not
really useful.
A default certificate is used when no "strict-sni" option is used on the bind
line. A default certificate is provided when the servername extension was not
used by the client, or when the servername does not match any configured
certificate.
Example:
bind *:443 default-crt foobar.pem.rsa default-crt foobar.pem.ecdsa crt website.pem.rsa
See also the "crt" keyword.
defer-accept
Is an optional keyword which is supported only on certain Linux kernels. It
states that a connection will only be accepted once some data arrive on it,

View File

@ -123,7 +123,7 @@ void ssl_async_fd_free(int fd);
#endif
struct issuer_chain* ssl_get0_issuer_chain(X509 *cert);
int ssl_load_global_issuer_from_BIO(BIO *in, char *fp, char **err);
int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err);
int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, int is_default, char **err);
int ssl_sock_load_srv_cert(char *path, struct server *server, int create_if_none, char **err);
void ssl_free_global_issuers(void);
int ssl_initialize_random(void);

View File

@ -777,6 +777,7 @@ static int bind_parse_ciphersuites(char **args, int cur_arg, struct proxy *px, s
static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
char path[MAXPATHLEN];
int default_crt = *args[cur_arg] == 'd' ? 1 : 0;
if (!*args[cur_arg + 1]) {
memprintf(err, "'%s' : missing certificate location", args[cur_arg]);
@ -789,10 +790,10 @@ static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bin
memprintf(err, "'%s' : path too long", args[cur_arg]);
return ERR_ALERT | ERR_FATAL;
}
return ssl_sock_load_cert(path, conf, err);
return ssl_sock_load_cert(path, conf, default_crt, err);
}
return ssl_sock_load_cert(args[cur_arg + 1], conf, err);
return ssl_sock_load_cert(args[cur_arg + 1], conf, default_crt, err);
}
/* parse the "crt-list" bind keyword. Returns a set of ERR_* flags possibly with an error in <err>. */
@ -2240,6 +2241,7 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
{ "crt-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth == 0 */
{ "crt-list", bind_parse_crt_list, 1 }, /* load a list of crt from this location */
{ "curves", bind_parse_curves, 1 }, /* set SSL curve suite */
{ "default-crt", bind_parse_crt, 1 }, /* load SSL certificates from this location */
{ "ecdhe", bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
{ "force-sslv3", bind_parse_tls_method_options, 0 }, /* force SSLv3 */
{ "force-tlsv10", bind_parse_tls_method_options, 0 }, /* force TLSv10 */

View File

@ -3760,19 +3760,20 @@ int ssl_sock_load_cert_list_file(char *file, int dir, struct bind_conf *bind_con
}
/* Returns a set of ERR_* flags possibly with an error in <err>. */
int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err)
int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, int is_default, char **err)
{
struct stat buf;
int cfgerr = 0;
struct ckch_store *ckchs;
struct ckch_inst *ckch_inst = NULL;
int found = 0; /* did we found a file to load ? */
int is_default = 0;
/* if the SNI trees were empty the first "crt" become a default certificate,
* it can be applied on multiple certificates if it's a bundle */
if (eb_is_empty(&bind_conf->sni_ctx) && eb_is_empty(&bind_conf->sni_w_ctx))
is_default = 1;
if (is_default == 0) {
if (eb_is_empty(&bind_conf->sni_ctx) && eb_is_empty(&bind_conf->sni_w_ctx))
is_default = 1;
}
if ((ckchs = ckchs_lookup(path))) {
/* we found the ckchs in the tree, we can use it directly */