]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: support ssl-min-ver and ssl-max-ver with crt-list
authorEmmanuel Hocdet <manu@gandi.net>
Thu, 18 May 2017 10:46:50 +0000 (12:46 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 2 Jun 2017 14:42:09 +0000 (16:42 +0200)
SSL/TLS version can be changed per certificat if and only if openssl lib support
earlier callback on handshake and, of course, is implemented in haproxy. It's ok
for BoringSSL. For Openssl, version 1.1.1 have such callback and could support it.

doc/configuration.txt
include/types/listener.h
src/ssl_sock.c

index 969734c69c54c8dcef1a97dc01fb21ec38a9a406..19c11323cd7aaafa127e8c85081fad61331f8a08 100644 (file)
@@ -10415,7 +10415,8 @@ crt-list <file>
         <crtfile> [\[<sslbindconf> ...\]] [[!]<snifilter> ...]
 
   sslbindconf support "npn", "alpn", "verify", "ca_file", "crl_file", "ecdhe",
-  "curves", "ciphers" configuration.
+  "curves", "ciphers" configuration. With BoringSSL "ssl-min-ver" and
+  "ssl-max-ver" are also supported.
   It override the configuration set in bind line for the certificate.
 
   Wildcards are supported in the SNI filter. Negative filter are also supported,
index 93f36624c609ff839e360e54e041fba316c50583..9a77e96544287d915777700301d23eec38d08c8c 100644 (file)
@@ -124,6 +124,7 @@ struct ssl_bind_conf {
        char *ciphers;             /* cipher suite to use if non-null */
        char *curves;              /* curves suite to use for ECDHE */
        char *ecdhe;               /* named curve to use for ECDHE */
+       struct tls_version_filter ssl_methods; /* ssl methods */
 #endif
 };
 
index 67fa2aebbff209af8863816e78d96be20adff1ab..776140f49b3166e18b8d2c1c0373426b6e1c7c71 100644 (file)
@@ -2106,8 +2106,15 @@ static int ssl_sock_switchctx_cbk(const struct ssl_early_callback_ctx *ctx)
        node = node_ecdsa ? node_ecdsa : (node_rsa ? node_rsa : node_anonymous);
 
        if (node) {
+               int min, max;
                /* switch ctx */
                ssl_sock_switchctx_set(ctx->ssl, container_of(node, struct sni_ctx, name)->ctx);
+               min = container_of(node, struct sni_ctx, name)->conf->ssl_methods.min;
+               if (min != s->ssl_methods.min)
+                       methodVersions[min].ssl_set_version(ctx->ssl, SET_MIN);
+               max = container_of(node, struct sni_ctx, name)->conf->ssl_methods.max;
+               if (max != s->ssl_methods.max)
+                       methodVersions[max].ssl_set_version(ctx->ssl, SET_MAX);
                return 1;
        }
        if (!s->strict_sni) {
@@ -3572,6 +3579,9 @@ ssl_sock_initial_ctx(struct bind_conf *bind_conf)
                        bind_conf->frontend->id, bind_conf->arg, bind_conf->file, bind_conf->line);
                cfgerr += 1;
        }
+       /* save real min/max in bind_conf */
+       conf_ssl_methods->min = min;
+       conf_ssl_methods->max = max;
 
 #if (OPENSSL_VERSION_NUMBER < 0x1010000fL) && !defined(OPENSSL_IS_BORINGSSL)
        /* Keep force-xxx implementation as it is in older haproxy. It's a
@@ -3623,6 +3633,36 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_
        const char *conf_ciphers;
        const char *conf_curves = NULL;
 
+       if (ssl_conf) {
+               struct tls_version_filter *conf_ssl_methods = &ssl_conf->ssl_methods;
+               int i, min, max;
+               int flags = MC_SSL_O_ALL;
+
+               /* Real min and max should be determinate with configuration and openssl's capabilities */
+               min = conf_ssl_methods->min ? conf_ssl_methods->min : bind_conf->ssl_methods.min;
+               max = conf_ssl_methods->max ? conf_ssl_methods->max : bind_conf->ssl_methods.max;
+               if (min)
+                       flags |= (methodVersions[min].flag - 1);
+               if (max)
+                       flags |= ~((methodVersions[max].flag << 1) - 1);
+               min = max = CONF_TLSV_NONE;
+               for (i = CONF_TLSV_MIN; i <= CONF_TLSV_MAX; i++)
+                       if (methodVersions[i].option && !(flags & methodVersions[i].flag)) {
+                               if (min)
+                                       max = i;
+                               else
+                                       min = max = i;
+                       }
+               /* save real min/max */
+               conf_ssl_methods->min = min;
+               conf_ssl_methods->max = max;
+               if (!min) {
+                       Alert("Proxy '%s': all SSL/TLS versions are disabled for bind '%s' at [%s:%d].\n",
+                             bind_conf->frontend->id, bind_conf->arg, bind_conf->file, bind_conf->line);
+                       cfgerr += 1;
+               }
+       }
+
        switch ((ssl_conf && ssl_conf->verify) ? ssl_conf->verify : bind_conf->ssl_conf.verify) {
                case SSL_SOCK_VERIFY_NONE:
                        verify = SSL_VERIFY_NONE;
@@ -6641,6 +6681,14 @@ static int parse_tls_method_minmax(char **args, int cur_arg, struct tls_version_
        return 0;
 }
 
+static int ssl_bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
+{
+#if !defined(OPENSSL_IS_BORINGSSL)
+       Warning("crt-list: ssl-min-ver and ssl-max-ver are not supported with this Openssl version (skipped).\n");
+#endif
+       return parse_tls_method_minmax(args, cur_arg, &conf->ssl_methods, err);
+}
+
 static int bind_parse_tls_method_minmax(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
        return parse_tls_method_minmax(args, cur_arg, &conf->ssl_methods, err);
@@ -7831,6 +7879,8 @@ static struct ssl_bind_kw ssl_bind_kws[] = {
        { "curves",                ssl_bind_parse_curves,           1 }, /* set SSL curve suite */
        { "ecdhe",                 ssl_bind_parse_ecdhe,            1 }, /* defines named curve for elliptic curve Diffie-Hellman */
        { "npn",                   ssl_bind_parse_npn,              1 }, /* set NPN supported protocols */
+       { "ssl-min-ver",           ssl_bind_parse_tls_method_minmax,1 }, /* minimum version */
+       { "ssl-max-ver",           ssl_bind_parse_tls_method_minmax,1 }, /* maximum version */
        { "verify",                ssl_bind_parse_verify,           1 }, /* set SSL verify method */
        { NULL, NULL, 0 },
 };