]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: ssl: Fix a memory leak in DHE key exchange
authorRemi Gacogne <rgacogne[at]aquaray[dot]fr>
Tue, 15 Jul 2014 09:36:40 +0000 (11:36 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 15 Jul 2014 14:07:05 +0000 (16:07 +0200)
OpenSSL does not free the DH * value returned by the callback specified with SSL_CTX_set_tmp_dh_callback(),
leading to a memory leak for SSL/TLS connections using Diffie Hellman Ephemeral key exchange.
This patch fixes the leak by allocating the DH * structs holding the DH parameters once, at configuration time.

Note: this fix must be backported to 1.5.

src/ssl_sock.c

index 375225d19f72c4bc797be651b96d4f75b7fd491f..cf8adc7f7efe4b204e3f60459fa4b439c3b5e07c 100644 (file)
@@ -105,6 +105,13 @@ enum {
 int sslconns = 0;
 int totalsslconns = 0;
 
+#ifndef OPENSSL_NO_DH
+static DH *local_dh_1024 = NULL;
+static DH *local_dh_2048 = NULL;
+static DH *local_dh_4096 = NULL;
+static DH *local_dh_8192 = NULL;
+#endif /* OPENSSL_NO_DH */
+
 #ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
 struct certificate_ocsp {
        struct ebmb_node key;
@@ -1034,16 +1041,16 @@ static DH *ssl_get_tmp_dh(SSL *ssl, int export, int keylen)
        }
 
        if (keylen >= 8192) {
-               dh = ssl_get_dh_8192();
+               dh = local_dh_8192;
        }
        else if (keylen >= 4096) {
-               dh = ssl_get_dh_4096();
+               dh = local_dh_4096;
        }
        else if (keylen >= 2048) {
-               dh = ssl_get_dh_2048();
+               dh = local_dh_2048;
        }
        else {
-               dh = ssl_get_dh_1024();
+               dh = local_dh_1024;
        }
 
        return dh;
@@ -1079,11 +1086,11 @@ int ssl_sock_load_dh_params(SSL_CTX *ctx, const char *file)
 
                if (global.tune.ssl_default_dh_param <= 1024) {
                        /* we are limited to DH parameter of 1024 bits anyway */
-                       dh = ssl_get_dh_1024();
-                       if (dh == NULL)
+                       local_dh_1024 = ssl_get_dh_1024();
+                       if (local_dh_1024 == NULL)
                                goto end;
 
-                       SSL_CTX_set_tmp_dh(ctx, dh);
+                       SSL_CTX_set_tmp_dh(ctx, local_dh_1024);
                }
                else {
                        SSL_CTX_set_tmp_dh_callback(ctx, ssl_get_tmp_dh);
@@ -1594,6 +1601,28 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy
                global.tune.ssl_default_dh_param = 1024;
        }
 
+#ifndef OPENSSL_NO_DH
+       if (global.tune.ssl_default_dh_param >= 1024) {
+               if (local_dh_1024 == NULL) {
+                       local_dh_1024 = ssl_get_dh_1024();
+               }
+               if (global.tune.ssl_default_dh_param >= 2048) {
+                       if (local_dh_2048 == NULL) {
+                               local_dh_2048 = ssl_get_dh_2048();
+                       }
+                       if (global.tune.ssl_default_dh_param >= 4096) {
+                               if (local_dh_4096 == NULL) {
+                                       local_dh_4096 = ssl_get_dh_4096();
+                               }
+                               if (global.tune.ssl_default_dh_param >= 8192 &&
+                                   local_dh_8192 == NULL) {
+                                       local_dh_8192 = ssl_get_dh_8192();
+                               }
+                       }
+               }
+       }
+#endif /* OPENSSL_NO_DH */
+
        SSL_CTX_set_info_callback(ctx, ssl_sock_infocbk);
 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
        SSL_CTX_set_msg_callback(ctx, ssl_sock_msgcbk);