]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: add the possibility to use a global DH parameters file
authorRemi Gacogne <rgacogne@aquaray.fr>
Fri, 29 May 2015 13:53:22 +0000 (15:53 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 31 May 2015 20:02:00 +0000 (22:02 +0200)
This patch adds the ssl-dh-param-file global setting. It sets the
default DH parameters that will be used during the SSL/TLS handshake when
ephemeral Diffie-Hellman (DHE) key exchange is used, for all "bind" lines
which do not explicitely define theirs.

doc/configuration.txt
include/proto/ssl_sock.h
src/cfgparse.c
src/ssl_sock.c

index 96766438f5587a7221c59da7161fa16d3b4a2548..655ede06cd9c8cff4f18d5764250b6d6a64c80dc 100644 (file)
@@ -766,6 +766,20 @@ ssl-default-server-options [<option>]...
   default ssl-options to force on all "server" lines. Please check the "server"
   keyword to see available options.
 
+ssl-dh-param-file <file>
+  This setting is only available when support for OpenSSL was built in. It sets
+  the default DH parameters that are used during the SSL/TLS handshake when
+  ephemeral Diffie-Hellman (DHE) key exchange is used, for all "bind" lines
+  which do not explicitely define theirs. It will be overridden by custom DH
+  parameters found in a bind certificate file if any. If custom DH parameters
+  are not specified either by using ssl-dh-param-file or by setting them directly
+  in the certificate file, pre-generated DH parameters of the size specified
+  by tune.ssl.default-dh-param will be used. Custom parameters are known to be
+  more secure and therefore their use is recommended.
+  Custom DH parameters may be generated by using the OpenSSL command
+  "openssl dhparam <size>", where size should be at least 2048, as 1024-bit DH
+  parameters should not be considered secure anymore.
+
 ssl-server-verify [none|required]
   The default behavior for SSL verify on servers side. If specified to 'none',
   servers certificates are not verified. The default is 'required' except if
@@ -1224,7 +1238,8 @@ tune.ssl.default-dh-param <number>
   this maximum value. Default value if 1024. Only 1024 or higher values are
   allowed. Higher values will increase the CPU load, and values greater than
   1024 bits are not supported by Java 7 and earlier clients. This value is not
-  used if static Diffie-Hellman parameters are supplied via the certificate file.
+  used if static Diffie-Hellman parameters are supplied either directly
+  in the certificate file or by using the ssl-dh-param-file parameter.
 
 tune.zlib.memlevel <number>
   Sets the memLevel parameter in zlib initialization for each session. It
index fa5eef56f694ae1a43b754bf9445d5cbf520dc21..4db516e5ff54d0ed7afa35000a2b848337020914 100644 (file)
@@ -64,6 +64,9 @@ struct tls_keys_ref *tlskeys_ref_lookup(const char *filename);
 struct tls_keys_ref *tlskeys_ref_lookupid(int unique_id);
 void tlskeys_finalize_config(void);
 #endif
+#ifndef OPENSSL_NO_DH
+int ssl_sock_load_global_dh_param_from_file(const char *filename);
+#endif
 
 #endif /* _PROTO_SSL_SOCK_H */
 
index 6d89b3d9cff9f17a76d8300daf908f757c52c3ff..7ffc0377f2540c44e1d7ca4815ef6d3e51c085b6 100644 (file)
@@ -753,6 +753,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                }
                global.tune.ssl_max_record = atol(args[1]);
        }
+#ifndef OPENSSL_NO_DH
        else if (!strcmp(args[0], "tune.ssl.default-dh-param")) {
                if (alertif_too_many_args(1, file, linenum, args, &err_code))
                        goto out;
@@ -768,6 +769,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                        goto out;
                }
        }
+#endif
 #endif
        else if (!strcmp(args[0], "tune.buffers.limit")) {
                if (alertif_too_many_args(1, file, linenum, args, &err_code))
@@ -1187,6 +1189,22 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                goto out;
 #endif
        }
+#ifdef USE_OPENSSL
+#ifndef OPENSSL_NO_DH
+       else if (!strcmp(args[0], "ssl-dh-param-file")) {
+               if (*(args[1]) == 0) {
+                       Alert("parsing [%s:%d] : '%s' expects a file path as an argument.\n", file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               if (ssl_sock_load_global_dh_param_from_file(args[1])) {
+                       Alert("parsing [%s:%d] : '%s': unable to load DH parameters from file <%s>.\n", file, linenum, args[0], args[1]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+       }
+#endif
+#endif
        else if (!strcmp(args[0], "ssl-server-verify")) {
                if (alertif_too_many_args(1, file, linenum, args, &err_code))
                        goto out;
index e528db2aec2dd3e8a57ef5423d4dd4ffcd4d03de..20a5324360508c2d3da0c028d1000c091385b3d3 100644 (file)
@@ -124,6 +124,7 @@ struct list tlskeys_reference = LIST_HEAD_INIT(tlskeys_reference);
 
 #ifndef OPENSSL_NO_DH
 static int ssl_dh_ptr_index = -1;
+static DH *global_dh = NULL;
 static DH *local_dh_1024 = NULL;
 static DH *local_dh_2048 = NULL;
 static DH *local_dh_4096 = NULL;
@@ -1332,22 +1333,44 @@ static DH *ssl_get_tmp_dh(SSL *ssl, int export, int keylen)
        return dh;
 }
 
-/* Loads Diffie-Hellman parameter from a file. Returns 1 if loaded, else -1
-   if an error occured, and 0 if parameter not found. */
-int ssl_sock_load_dh_params(SSL_CTX *ctx, const char *file)
+static DH * ssl_sock_get_dh_from_file(const char *filename)
 {
-       int ret = -1;
-       BIO *in;
        DH *dh = NULL;
+       BIO *in = BIO_new(BIO_s_file());
 
-       in = BIO_new(BIO_s_file());
        if (in == NULL)
                goto end;
 
-       if (BIO_read_filename(in, file) <= 0)
+       if (BIO_read_filename(in, filename) <= 0)
                goto end;
 
-       dh = PEM_read_bio_DHparams(in, NULL, ctx->default_passwd_callback, ctx->default_passwd_callback_userdata);
+       dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
+
+end:
+        if (in)
+                BIO_free(in);
+
+       return dh;
+}
+
+int ssl_sock_load_global_dh_param_from_file(const char *filename)
+{
+       global_dh = ssl_sock_get_dh_from_file(filename);
+
+       if (global_dh) {
+               return 0;
+       }
+
+       return -1;
+}
+
+/* Loads Diffie-Hellman parameter from a file. Returns 1 if loaded, else -1
+   if an error occured, and 0 if parameter not found. */
+int ssl_sock_load_dh_params(SSL_CTX *ctx, const char *file)
+{
+       int ret = -1;
+       DH *dh = ssl_sock_get_dh_from_file(file);
+
        if (dh) {
                ret = 1;
                SSL_CTX_set_tmp_dh(ctx, dh);
@@ -1358,6 +1381,10 @@ int ssl_sock_load_dh_params(SSL_CTX *ctx, const char *file)
                        SSL_CTX_set_ex_data(ctx, ssl_dh_ptr_index, dh);
                }
        }
+       else if (global_dh) {
+               SSL_CTX_set_tmp_dh(ctx, global_dh);
+               ret = 0; /* DH params not found */
+       }
        else {
                /* Clear openssl global errors stack */
                ERR_clear_error();
@@ -1381,9 +1408,6 @@ end:
        if (dh)
                DH_free(dh);
 
-       if (in)
-               BIO_free(in);
-
        return ret;
 }
 #endif
@@ -1901,9 +1925,11 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy
                cfgerr++;
        }
 
-       /* If tune.ssl.default-dh-param has not been set and
-          no static DH params were in the certificate file. */
+       /* If tune.ssl.default-dh-param has not been set,
+          neither has ssl-default-dh-file and no static DH
+          params were in the certificate file. */
        if (global.tune.ssl_default_dh_param == 0 &&
+           global_dh == NULL &&
            (ssl_dh_ptr_index == -1 ||
             SSL_CTX_get_ex_data(ctx, ssl_dh_ptr_index) == NULL)) {
 
@@ -5083,6 +5109,11 @@ static void __ssl_sock_deinit(void)
                 DH_free(local_dh_8192);
                 local_dh_8192 = NULL;
         }
+
+       if (global_dh) {
+               DH_free(global_dh);
+               global_dh = NULL;
+       }
 #endif
 
         ERR_remove_state(0);