+From 60d7aeb6e1450995e721d01f48f60b7db4c44e2b Mon Sep 17 00:00:00 2001
+From: Remi Gacogne <rgacogne[at]aquaray[dot]fr>
+Date: Tue, 15 Jul 2014 11:36:40 +0200
+Subject: [PATCH 3/3] BUG/MEDIUM: ssl: Fix a memory leak in DHE key exchange
+
+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.
+(cherry picked from commit 8de5415b85512da871d58d1e9a0a33bd67f3b570)
+---
+ src/ssl_sock.c | 43 ++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 36 insertions(+), 7 deletions(-)
+
+diff --git a/src/ssl_sock.c b/src/ssl_sock.c
+index 375225d..cf8adc7 100644
+--- a/src/ssl_sock.c
++++ b/src/ssl_sock.c
+@@ -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);
+--
+1.8.5.5
+