]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: implements 'default-crt' keyword for bind Lines
authorWilliam Lallemand <wlallemand@haproxy.com>
Fri, 12 Jan 2024 16:32:48 +0000 (17:32 +0100)
committerWilliam Lallemand <wlallemand@haproxy.com>
Fri, 12 Jan 2024 16:40:42 +0000 (17:40 +0100)
The 'default-crt' bind keyword allows to specify multiples
default/fallback certificates, allowing one to have an RSA as well as an
ECDSA default.

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

index 9008fc0468ac5a340d51b642434e233baeeb2b79..d9b7b8b6adc97c66d60a3d1f2739f9742d6d8b00 100644 (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,
index 0befb570cca21cd2d4d5ebae955ad5d77391d297..773bb320a0697946a1b34b6915a003bbb681fb36 100644 (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);
index 56663367706dc0b334946c4c27fa4909d98b3e32..3f728258dd141fa4561b7a1881abf05b51a9a5ef 100644 (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 */
index 0c5fe96f229729a221ccb7cfc05349ef312bf803..c5603d25e090a806076b8852415db18ba4239c5b 100644 (file)
@@ -3760,19 +3760,20 @@ error:
 }
 
 /* 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 */