MAJOR: ssl: bind configuration per certificat

crt-list is extend to support ssl configuration. You can now have
such line in crt-list <file>:
mycert.pem [npn h2,http/1.1]

Support include "npn", "alpn", "verify", "ca_file", "crl_file",
"ecdhe", "ciphers" configuration and ssl options.

"crt-base" is also supported to fetch certificates.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 739fad9..abb36df 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -10248,10 +10248,14 @@
 
 crt-list <file>
   This setting is only available when support for OpenSSL was built in. It
-  designates a list of PEM file with an optional list of SNI filter per
-  certificate, with the following format for each line :
+  designates a list of PEM file with an optional ssl configuration and a SNI
+  filter per certificate, with the following format for each line :
 
-        <crtfile> [[!]<snifilter> ...]
+        <crtfile> [\[<sslbindconf> ...\]] [[!]<snifilter> ...]
+
+  sslbindconf support "npn", "alpn", "verify", "ca_file", "crl_file", "ecdhe",
+  "ciphers" configuration and ssl options (see "ssl-default-bind-options").
+  It override the configuration set in bind line for the certificate.
 
   Wildcards are supported in the SNI filter. Negative filter are also supported,
   only useful in combination with a wildcard filter to exclude a particular SNI.
@@ -10266,6 +10270,12 @@
   the base name is given in the crt-list. SNI filter will do the same work on
   all bundled certificates.
 
+  crt-list file example:
+        cert1.pem
+        cert2.pem [npn h2,http/1.1]
+        certW.pem                   *.domain.tld !secure.domain.tld
+        certS.pem [ecdhe secp521r1 ciphers ECDHE-ECDSA-AES256-GCM-SHA384] secure.domain.tld
+
 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,
diff --git a/include/common/defaults.h b/include/common/defaults.h
index 3e04f02..1618ab4 100644
--- a/include/common/defaults.h
+++ b/include/common/defaults.h
@@ -74,8 +74,11 @@
 // max # args on a configuration line
 #define MAX_LINE_ARGS   64
 
-// crt-list parsing factor for LINESIZE and MAX_LINE_ARGS
-#define CRTLIST_FACTOR  32
+// maximum line size when parsing crt-bind-list config
+#define CRT_LINESIZE    65536
+
+// max # args on crt-bind-list configuration line
+#define MAX_CRT_ARGS  2048
 
 // max # args on a stats socket
 // This should cover at least 5 + twice the # of data_types
diff --git a/include/proto/ssl_sock.h b/include/proto/ssl_sock.h
index 9f43adc..6f779fa 100644
--- a/include/proto/ssl_sock.h
+++ b/include/proto/ssl_sock.h
@@ -42,7 +42,7 @@
 }
 
 int ssl_sock_handshake(struct connection *conn, unsigned int flag);
-int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx);
+int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *, SSL_CTX *ctx);
 int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf);
 int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf);
 int ssl_sock_prepare_srv_ctx(struct server *srv);
diff --git a/include/types/listener.h b/include/types/listener.h
index 03f4a72..b534c47 100644
--- a/include/types/listener.h
+++ b/include/types/listener.h
@@ -115,22 +115,34 @@
 #define BC_SSL_O_NO_TLS_TICKETS 0x0100	/* disable session resumption tickets */
 #endif
 
-/* "bind" line settings */
-struct bind_conf {
+/* ssl "bind" settings */
+struct ssl_bind_conf {
 #ifdef USE_OPENSSL
+#ifdef OPENSSL_NPN_NEGOTIATED
+	char *npn_str;             /* NPN protocol string */
+	int npn_len;               /* NPN protocol string length */
+#endif
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+	char *alpn_str;            /* ALPN protocol string */
+	int alpn_len;              /* ALPN protocol string length */
+#endif
+	int verify;                /* verify method (set of SSL_VERIFY_* flags) */
 	char *ca_file;             /* CAfile to use on verify */
-	unsigned long long ca_ignerr;  /* ignored verify errors in handshake if depth > 0 */
-	unsigned long long crt_ignerr; /* ignored verify errors in handshake if depth == 0 */
-	char *ciphers;             /* cipher suite to use if non-null */
 	char *crl_file;            /* CRLfile to use on verify */
+	char *ciphers;             /* cipher suite to use if non-null */
 	char *ecdhe;               /* named curve to use for ECDHE */
 	int ssl_options;           /* ssl options */
-	int verify;                /* verify method (set of SSL_VERIFY_* flags) */
+#endif
+};
+
+/* "bind" line settings */
+struct bind_conf {
+#ifdef USE_OPENSSL
+	struct ssl_bind_conf ssl_conf; /* ssl conf for ctx setting */
+	unsigned long long ca_ignerr;  /* ignored verify errors in handshake if depth > 0 */
+	unsigned long long crt_ignerr; /* ignored verify errors in handshake if depth == 0 */
 	SSL_CTX *default_ctx;      /* SSL context of first/default certificate */
-	char *npn_str;             /* NPN protocol string */
-	int npn_len;               /* NPN protocol string length */
-	char *alpn_str;            /* ALPN protocol string */
-	int alpn_len;              /* ALPN protocol string length */
+	struct ssl_bind_conf *default_ssl_conf; /* custom SSL conf of default_ctx */
 	int strict_sni;            /* refuse negotiation if sni doesn't match a certificate */
 	struct eb_root sni_ctx;    /* sni_ctx tree of all known certs full-names sorted by name */
 	struct eb_root sni_w_ctx;  /* sni_ctx tree of all known certs wildcards sorted by name */
@@ -213,6 +225,11 @@
 	int (*parse)(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err);
 	int skip; /* nb of args to skip */
 };
+struct ssl_bind_kw {
+	const char *kw;
+	int (*parse)(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err);
+	int skip; /* nb of args to skip */
+};
 
 /*
  * A keyword list. It is a NULL-terminated array of keywords. It embeds a
diff --git a/include/types/ssl_sock.h b/include/types/ssl_sock.h
index e71ba79..a384f05 100644
--- a/include/types/ssl_sock.h
+++ b/include/types/ssl_sock.h
@@ -22,6 +22,7 @@
 #ifndef _TYPES_SSL_SOCK_H
 #define _TYPES_SSL_SOCK_H
 
+#include <types/listener.h>
 #include <openssl/ssl.h>
 #include <ebmbtree.h>
 
@@ -29,6 +30,7 @@
 	SSL_CTX *ctx;             /* context associated to the certificate */
 	int order;                /* load order for the certificate */
 	int neg;                  /* reject if match */
+	struct ssl_bind_conf *conf; /* ssl "bind" conf for the certificate */
 	struct ebmb_node name;    /* node holding the servername value */
 };
 
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 3705917..b94166c 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -194,6 +194,8 @@
 	"nonRepudiation,digitalSignature,keyEncipherment"
 };
 
+static struct ssl_bind_kw ssl_bind_kws[];
+
 /* LRU cache to store generated certificate */
 static struct lru64_head *ssl_ctx_lru_tree = NULL;
 static unsigned int       ssl_ctx_lru_seed = 0;
@@ -1182,7 +1184,7 @@
 static int ssl_sock_advertise_npn_protos(SSL *s, const unsigned char **data,
                                          unsigned int *len, void *arg)
 {
-	struct bind_conf *conf = arg;
+	struct ssl_bind_conf *conf = arg;
 
 	*data = (const unsigned char *)conf->npn_str;
 	*len = conf->npn_len;
@@ -1199,7 +1201,7 @@
                                           const unsigned char *server,
                                           unsigned int server_len, void *arg)
 {
-	struct bind_conf *conf = arg;
+	struct ssl_bind_conf *conf = arg;
 
 	if (SSL_select_next_proto((unsigned char**) out, outlen, (const unsigned char *)conf->alpn_str,
 	                          conf->alpn_len, server, server_len) != OPENSSL_NPN_NEGOTIATED) {
@@ -1330,7 +1332,7 @@
 	SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_get_tmp_dh);
 #if defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH)
 	{
-		const char *ecdhe = (bind_conf->ecdhe ? bind_conf->ecdhe : ECDHE_DEFAULT_CURVE);
+		const char *ecdhe = (bind_conf->ssl_conf.ecdhe ? bind_conf->ssl_conf.ecdhe : ECDHE_DEFAULT_CURVE);
 		EC_KEY     *ecc;
 		int         nid;
 
@@ -1776,7 +1778,8 @@
 }
 #endif
 
-static int ssl_sock_add_cert_sni(SSL_CTX *ctx, struct bind_conf *s, char *name, int order)
+static int ssl_sock_add_cert_sni(SSL_CTX *ctx, struct bind_conf *s,
+				 struct ssl_bind_conf *conf, char *name, int order)
 {
 	struct sni_ctx *sc;
 	int wild = 0, neg = 0;
@@ -1809,7 +1812,7 @@
 			node = ebst_lookup(&s->sni_ctx, trash.str);
 		for (; node; node = ebmb_next_dup(node)) {
 			sc = ebmb_entry(node, struct sni_ctx, name);
-			if (sc->ctx == ctx && sc->neg == neg)
+			if (sc->ctx == ctx && sc->conf == conf && sc->neg == neg)
 				return order;
 		}
 
@@ -1818,6 +1821,7 @@
 			return order;
 		memcpy(sc->name.key, trash.str, len + 1);
 		sc->ctx = ctx;
+		sc->conf = conf;
 		sc->order = order++;
 		sc->neg = neg;
 		if (wild)
@@ -2072,7 +2076,8 @@
  *     0 on success
  *     1 on failure
  */
-static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, char **sni_filter, int fcount, char **err)
+static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf,
+				    char **sni_filter, int fcount, char **err)
 {
 	char fp[MAXPATHLEN+1] = {0};
 	int n = 0;
@@ -2246,7 +2251,7 @@
 		}
 
 		/* Update SNI Tree */
-		key_combos[i-1].order = ssl_sock_add_cert_sni(cur_ctx, bind_conf, str, key_combos[i-1].order);
+		key_combos[i-1].order = ssl_sock_add_cert_sni(cur_ctx, bind_conf, ssl_conf, str, key_combos[i-1].order);
 		node = ebmb_next(node);
 	}
 
@@ -2256,6 +2261,7 @@
 		for (i = SSL_SOCK_POSSIBLE_KT_COMBOS - 1; i >= 0; i--) {
 			if (key_combos[i].ctx) {
 				bind_conf->default_ctx = key_combos[i].ctx;
+				bind_conf->default_ssl_conf = ssl_conf;
 				break;
 			}
 		}
@@ -2280,7 +2286,8 @@
 }
 #else
 /* This is a dummy, that just logs an error and returns error */
-static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, char **sni_filter, int fcount, char **err)
+static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf,
+				    char **sni_filter, int fcount, char **err)
 {
 	memprintf(err, "%sunable to stat SSL certificate from file '%s' : %s.\n",
 	          err && *err ? *err : "", path, strerror(errno));
@@ -2292,7 +2299,8 @@
 /* Loads a certificate key and CA chain from a file. Returns 0 on error, -1 if
  * an early error happens and the caller must call SSL_CTX_free() by itelf.
  */
-static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct bind_conf *s, char **sni_filter, int fcount)
+static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct bind_conf *s,
+					 struct ssl_bind_conf *ssl_conf, char **sni_filter, int fcount)
 {
 	BIO *in;
 	X509 *x = NULL, *ca;
@@ -2325,7 +2333,7 @@
 
 	if (fcount) {
 		while (fcount--)
-			order = ssl_sock_add_cert_sni(ctx, s, sni_filter[fcount], order);
+			order = ssl_sock_add_cert_sni(ctx, s, ssl_conf, sni_filter[fcount], order);
 	}
 	else {
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@@ -2335,7 +2343,7 @@
 				GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
 				if (name->type == GEN_DNS) {
 					if (ASN1_STRING_to_UTF8((unsigned char **)&str, name->d.dNSName) >= 0) {
-						order = ssl_sock_add_cert_sni(ctx, s, str, order);
+						order = ssl_sock_add_cert_sni(ctx, s, ssl_conf, str, order);
 						OPENSSL_free(str);
 					}
 				}
@@ -2351,7 +2359,7 @@
 
 			value = X509_NAME_ENTRY_get_data(entry);
 			if (ASN1_STRING_to_UTF8((unsigned char **)&str, value) >= 0) {
-				order = ssl_sock_add_cert_sni(ctx, s, str, order);
+				order = ssl_sock_add_cert_sni(ctx, s, ssl_conf, str, order);
 				OPENSSL_free(str);
 			}
 		}
@@ -2394,7 +2402,8 @@
 	return ret;
 }
 
-static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf, char **sni_filter, int fcount, char **err)
+static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf,
+				   char **sni_filter, int fcount, char **err)
 {
 	int ret;
 	SSL_CTX *ctx;
@@ -2413,7 +2422,7 @@
 		return 1;
 	}
 
-	ret = ssl_sock_load_cert_chain_file(ctx, path, bind_conf, sni_filter, fcount);
+	ret = ssl_sock_load_cert_chain_file(ctx, path, bind_conf, ssl_conf, sni_filter, fcount);
 	if (ret <= 0) {
 		memprintf(err, "%sunable to load SSL certificate from PEM file '%s'.\n",
 		          err && *err ? *err : "", path);
@@ -2476,8 +2485,10 @@
 		return 1;
 	}
 #endif
-	if (!bind_conf->default_ctx)
+	if (!bind_conf->default_ctx) {
 		bind_conf->default_ctx = ctx;
+		bind_conf->default_ssl_conf = ssl_conf;
+	}
 
 	return 0;
 }
@@ -2499,7 +2510,7 @@
 	if (stat(path, &buf) == 0) {
 		dir = opendir(path);
 		if (!dir)
-			return ssl_sock_load_cert_file(path, bind_conf, NULL, 0, err);
+			return ssl_sock_load_cert_file(path, bind_conf, NULL, NULL, 0, err);
 
 		/* strip trailing slashes, including first one */
 		for (end = path + strlen(path) - 1; end >= path && *end == '/'; end--)
@@ -2559,7 +2570,7 @@
 						}
 
 						snprintf(fp, sizeof(fp), "%s/%s", path, dp);
-						ssl_sock_load_multi_cert(fp, bind_conf, NULL, 0, err);
+						ssl_sock_load_multi_cert(fp, bind_conf, NULL, NULL, 0, err);
 
 						/* Successfully processed the bundle */
 						goto ignore_entry;
@@ -2567,7 +2578,7 @@
 				}
 
 #endif
-				cfgerr += ssl_sock_load_cert_file(fp, bind_conf, NULL, 0, err);
+				cfgerr += ssl_sock_load_cert_file(fp, bind_conf, NULL, NULL, 0, err);
 ignore_entry:
 				free(de);
 			}
@@ -2577,7 +2588,7 @@
 		return cfgerr;
 	}
 
-	cfgerr = ssl_sock_load_multi_cert(path, bind_conf, NULL, 0, err);
+	cfgerr = ssl_sock_load_multi_cert(path, bind_conf, NULL, NULL, 0, err);
 
 	return cfgerr;
 }
@@ -2598,9 +2609,33 @@
 	return random_initialized;
 }
 
-int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, char **err)
+/* release ssl bind conf */
+void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf)
 {
-	char thisline[LINESIZE*CRTLIST_FACTOR];
+	if (conf) {
+#ifdef OPENSSL_NPN_NEGOTIATED
+		free(conf->npn_str);
+		conf->npn_str = NULL;
+#endif
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+		free(conf->alpn_str);
+		conf->alpn_str = NULL;
+#endif
+		free(conf->ca_file);
+		conf->ca_file = NULL;
+		free(conf->crl_file);
+		conf->crl_file = NULL;
+		free(conf->ciphers);
+		conf->ciphers = NULL;
+		free(conf->ecdhe);
+		conf->ecdhe = NULL;
+	}
+}
+
+int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, struct proxy *curproxy, char **err)
+{
+	char thisline[CRT_LINESIZE];
+	char path[MAXPATHLEN+1];
 	FILE *f;
 	struct stat buf;
 	int linenum = 0;
@@ -2612,11 +2647,12 @@
 	}
 
 	while (fgets(thisline, sizeof(thisline), f) != NULL) {
-		int arg;
-		int newarg;
+		int arg, newarg, cur_arg, i, ssl_b = 0, ssl_e = 0;
 		char *end;
-		char *args[MAX_LINE_ARGS*CRTLIST_FACTOR + 1];
+		char *args[MAX_CRT_ARGS + 1];
 		char *line = thisline;
+		char *crt_path;
+		struct ssl_bind_conf *ssl_conf = NULL;
 
 		linenum++;
 		end = line + strlen(line);
@@ -2637,18 +2673,43 @@
 				/* end of string, end of loop */
 				*line = 0;
 				break;
-			}
-			else if (isspace(*line)) {
+			} else if (isspace(*line)) {
 				newarg = 1;
 				*line = 0;
-			}
-			else if (newarg) {
-				if (arg == MAX_LINE_ARGS*CRTLIST_FACTOR) {
-					memprintf(err, "too many args on line %d in file '%s'.",
-						  linenum, file);
+			} else if (*line == '[') {
+				if (ssl_b) {
+					memprintf(err, "too many '[' on line %d in file '%s'.", linenum, file);
+					cfgerr = 1;
+					break;
+				}
+				if (!arg) {
+					memprintf(err, "file must start with a cert on line %d in file '%s'", linenum, file);
+					cfgerr = 1;
+					break;
+				}
+				ssl_b = arg;
+				newarg = 1;
+				*line = 0;
+			} else if (*line == ']') {
+				if (ssl_e) {
+					memprintf(err, "too many ']' on line %d in file '%s'.", linenum, file);
 					cfgerr = 1;
 					break;
 				}
+				if (!ssl_b) {
+					memprintf(err, "missing '[' in line %d in file '%s'.", linenum, file);
+					cfgerr = 1;
+					break;
+				}
+				ssl_e = arg;
+				newarg = 1;
+				*line = 0;
+			} else if (newarg) {
+				if (arg == MAX_CRT_ARGS) {
+					memprintf(err, "too many args on line %d in file '%s'.", linenum, file);
+					cfgerr = 1;
+					break;
+				}
 				newarg = 0;
 				args[arg++] = line;
 			}
@@ -2656,15 +2717,61 @@
 		}
 		if (cfgerr)
 			break;
+		args[arg++] = line;
 
 		/* empty line */
-		if (!arg)
+		if (!*args[0])
 			continue;
 
-		if (stat(args[0], &buf) == 0) {
-			cfgerr = ssl_sock_load_cert_file(args[0], bind_conf, &args[1], arg-1, err);
+		crt_path = args[0];
+		if (*crt_path != '/' && global_ssl.crt_base) {
+			if ((strlen(global_ssl.crt_base) + 1 + strlen(crt_path)) > MAXPATHLEN) {
+				memprintf(err, "'%s' : path too long on line %d in file '%s'",
+					  crt_path, linenum, file);
+				cfgerr = 1;
+				break;
+			}
+			snprintf(path, sizeof(path), "%s/%s",  global_ssl.crt_base, crt_path);
+			crt_path = path;
+		}
+
+		ssl_conf = calloc(1, sizeof *ssl_conf);
+		cur_arg = ssl_b ? ssl_b : 1;
+		while (cur_arg < ssl_e) {
+			newarg = 0;
+			for (i = 0; ssl_bind_kws[i].kw != NULL; i++) {
+				if (strcmp(ssl_bind_kws[i].kw, args[cur_arg]) == 0) {
+					newarg = 1;
+					cfgerr = ssl_bind_kws[i].parse(args, cur_arg, curproxy, ssl_conf, err);
+					if (cur_arg + 1 + ssl_bind_kws[i].skip > ssl_e) {
+						memprintf(err, "ssl args out of '[]' for %s on line %d in file '%s'",
+							  args[cur_arg], linenum, file);
+						cfgerr = 1;
+					}
+					cur_arg += 1 + ssl_bind_kws[i].skip;
+					break;
+				}
+			}
+			if (!cfgerr && !newarg) {
+				memprintf(err, "unknown ssl keyword %s on line %d in file '%s'.",
+					  args[cur_arg], linenum, file);
+				cfgerr = 1;
+				break;
+			}
+		}
+		if (cfgerr) {
+			ssl_sock_free_ssl_conf(ssl_conf);
+			free(ssl_conf);
+			ssl_conf = NULL;
+			break;
+		}
+
+		if (stat(crt_path, &buf) == 0) {
+			cfgerr = ssl_sock_load_cert_file(crt_path, bind_conf, ssl_conf,
+							 &args[cur_arg], arg - cur_arg - 1, err);
 		} else {
-			cfgerr = ssl_sock_load_multi_cert(args[0], bind_conf, &args[1], arg-1, err);
+			cfgerr = ssl_sock_load_multi_cert(crt_path, bind_conf, ssl_conf,
+							  &args[cur_arg], arg - cur_arg - 1, err);
 		}
 
 		if (cfgerr) {
@@ -2712,7 +2819,7 @@
 #define SSL_MODE_SMALL_BUFFERS 0
 #endif
 
-int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx)
+int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf, SSL_CTX *ctx)
 {
 	struct proxy *curproxy = bind_conf->frontend;
 	int cfgerr = 0;
@@ -2741,6 +2848,9 @@
 	int idx = 0;
 	int dhe_found = 0;
 	SSL *ssl = NULL;
+	struct ssl_bind_conf *ssl_conf_cur;
+	int conf_ssl_options = bind_conf->ssl_conf.ssl_options | (ssl_conf ? ssl_conf->ssl_options : 0);
+	const char *conf_ciphers;
 
 	/* Make sure openssl opens /dev/urandom before the chroot */
 	if (!ssl_initialize_random()) {
@@ -2748,17 +2858,17 @@
 		cfgerr++;
 	}
 
-	if (bind_conf->ssl_options & BC_SSL_O_NO_SSLV3)
+	if (conf_ssl_options & BC_SSL_O_NO_SSLV3)
 		ssloptions |= SSL_OP_NO_SSLv3;
-	if (bind_conf->ssl_options & BC_SSL_O_NO_TLSV10)
+	if (conf_ssl_options & BC_SSL_O_NO_TLSV10)
 		ssloptions |= SSL_OP_NO_TLSv1;
-	if (bind_conf->ssl_options & BC_SSL_O_NO_TLSV11)
+	if (conf_ssl_options & BC_SSL_O_NO_TLSV11)
 		ssloptions |= SSL_OP_NO_TLSv1_1;
-	if (bind_conf->ssl_options & BC_SSL_O_NO_TLSV12)
+	if (conf_ssl_options & BC_SSL_O_NO_TLSV12)
 		ssloptions |= SSL_OP_NO_TLSv1_2;
-	if (bind_conf->ssl_options & BC_SSL_O_NO_TLS_TICKETS)
+	if (conf_ssl_options & BC_SSL_O_NO_TLS_TICKETS)
 		ssloptions |= SSL_OP_NO_TICKET;
-	if (bind_conf->ssl_options & BC_SSL_O_USE_SSLV3) {
+	if (conf_ssl_options & BC_SSL_O_USE_SSLV3) {
 #ifndef OPENSSL_NO_SSL3
 		SSL_CTX_set_ssl_version(ctx, SSLv3_server_method());
 #else
@@ -2766,20 +2876,20 @@
 		cfgerr++;
 #endif
 	}
-	if (bind_conf->ssl_options & BC_SSL_O_USE_TLSV10)
+	if (conf_ssl_options & BC_SSL_O_USE_TLSV10)
 		SSL_CTX_set_ssl_version(ctx, TLSv1_server_method());
 #if SSL_OP_NO_TLSv1_1
-	if (bind_conf->ssl_options & BC_SSL_O_USE_TLSV11)
+	if (conf_ssl_options & BC_SSL_O_USE_TLSV11)
 		SSL_CTX_set_ssl_version(ctx, TLSv1_1_server_method());
 #endif
 #if SSL_OP_NO_TLSv1_2
-	if (bind_conf->ssl_options & BC_SSL_O_USE_TLSV12)
+	if (conf_ssl_options & BC_SSL_O_USE_TLSV12)
 		SSL_CTX_set_ssl_version(ctx, TLSv1_2_server_method());
 #endif
 
 	SSL_CTX_set_options(ctx, ssloptions);
 	SSL_CTX_set_mode(ctx, sslmode);
-	switch (bind_conf->verify) {
+	switch ((ssl_conf && ssl_conf->verify) ? ssl_conf->verify : bind_conf->ssl_conf.verify) {
 		case SSL_SOCK_VERIFY_NONE:
 			verify = SSL_VERIFY_NONE;
 			break;
@@ -2792,15 +2902,17 @@
 	}
 	SSL_CTX_set_verify(ctx, verify, ssl_sock_bind_verifycbk);
 	if (verify & SSL_VERIFY_PEER) {
-		if (bind_conf->ca_file) {
+		char *ca_file = (ssl_conf && ssl_conf->ca_file) ? ssl_conf->ca_file : bind_conf->ssl_conf.ca_file;
+		char *crl_file = (ssl_conf && ssl_conf->crl_file) ? ssl_conf->crl_file : bind_conf->ssl_conf.crl_file;
+		if (ca_file) {
 			/* load CAfile to verify */
-			if (!SSL_CTX_load_verify_locations(ctx, bind_conf->ca_file, NULL)) {
+			if (!SSL_CTX_load_verify_locations(ctx, ca_file, NULL)) {
 				Alert("Proxy '%s': unable to load CA file '%s' for bind '%s' at [%s:%d].\n",
-				      curproxy->id, bind_conf->ca_file, bind_conf->arg, bind_conf->file, bind_conf->line);
+				      curproxy->id, ca_file, bind_conf->arg, bind_conf->file, bind_conf->line);
 				cfgerr++;
 			}
 			/* set CA names fo client cert request, function returns void */
-			SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(bind_conf->ca_file));
+			SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(ca_file));
 		}
 		else {
 			Alert("Proxy '%s': verify is enabled but no CA file specified for bind '%s' at [%s:%d].\n",
@@ -2808,12 +2920,12 @@
 			cfgerr++;
 		}
 #ifdef X509_V_FLAG_CRL_CHECK
-		if (bind_conf->crl_file) {
+		if (crl_file) {
 			X509_STORE *store = SSL_CTX_get_cert_store(ctx);
 
-			if (!store || !X509_STORE_load_locations(store, bind_conf->crl_file, NULL)) {
+			if (!store || !X509_STORE_load_locations(store, crl_file, NULL)) {
 				Alert("Proxy '%s': unable to configure CRL file '%s' for bind '%s' at [%s:%d].\n",
-				      curproxy->id, bind_conf->crl_file, bind_conf->arg, bind_conf->file, bind_conf->line);
+				      curproxy->id, crl_file, bind_conf->arg, bind_conf->file, bind_conf->line);
 				cfgerr++;
 			}
 			else {
@@ -2838,10 +2950,11 @@
 		SSL_CTX_set_timeout(ctx, global_ssl.life_time);
 
 	shared_context_set_cache(ctx);
-	if (bind_conf->ciphers &&
-	    !SSL_CTX_set_cipher_list(ctx, bind_conf->ciphers)) {
+	conf_ciphers = (ssl_conf && ssl_conf->ciphers) ? ssl_conf->ciphers : bind_conf->ssl_conf.ciphers;
+	if (conf_ciphers &&
+	    !SSL_CTX_set_cipher_list(ctx, conf_ciphers)) {
 		Alert("Proxy '%s': unable to set SSL cipher list to '%s' for bind '%s' at [%s:%d].\n",
-		curproxy->id, bind_conf->ciphers, bind_conf->arg, bind_conf->file, bind_conf->line);
+		curproxy->id, conf_ciphers, bind_conf->arg, bind_conf->file, bind_conf->line);
 		cfgerr++;
 	}
 
@@ -2905,12 +3018,22 @@
 #endif
 
 #ifdef OPENSSL_NPN_NEGOTIATED
-	if (bind_conf->npn_str)
-		SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_sock_advertise_npn_protos, bind_conf);
+	ssl_conf_cur = NULL;
+	if (ssl_conf && ssl_conf->npn_str)
+		ssl_conf_cur = ssl_conf;
+	else if (bind_conf->ssl_conf.npn_str)
+		ssl_conf_cur = &bind_conf->ssl_conf;
+	if (ssl_conf_cur)
+		SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_sock_advertise_npn_protos, ssl_conf_cur);
 #endif
 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
-	if (bind_conf->alpn_str)
-		SSL_CTX_set_alpn_select_cb(ctx, ssl_sock_advertise_alpn_protos, bind_conf);
+	ssl_conf_cur = NULL;
+	if (ssl_conf && ssl_conf->alpn_str)
+		ssl_conf_cur = ssl_conf;
+	else if (bind_conf->ssl_conf.alpn_str)
+		ssl_conf_cur = &bind_conf->ssl_conf;
+	if (ssl_conf_cur)
+		SSL_CTX_set_alpn_select_cb(ctx, ssl_sock_advertise_alpn_protos, ssl_conf_cur);
 #endif
 
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@@ -2921,12 +3044,13 @@
 	{
 		int i;
 		EC_KEY  *ecdh;
+		const char *ecdhe = (ssl_conf && ssl_conf->ecdhe) ? ssl_conf->ecdhe :
+			(bind_conf->ssl_conf.ecdhe ? bind_conf->ssl_conf.ecdhe : ECDHE_DEFAULT_CURVE);
 
-		i = OBJ_sn2nid(bind_conf->ecdhe ? bind_conf->ecdhe : ECDHE_DEFAULT_CURVE);
+		i = OBJ_sn2nid(ecdhe);
 		if (!i || ((ecdh = EC_KEY_new_by_curve_name(i)) == NULL)) {
 			Alert("Proxy '%s': unable to set elliptic named curve to '%s' for bind '%s' at [%s:%d].\n",
-			      curproxy->id, bind_conf->ecdhe ? bind_conf->ecdhe : ECDHE_DEFAULT_CURVE,
-			      bind_conf->arg, bind_conf->file, bind_conf->line);
+			      curproxy->id, ecdhe, bind_conf->arg, bind_conf->file, bind_conf->line);
 			cfgerr++;
 		}
 		else {
@@ -3241,7 +3365,7 @@
 	global.ssl_used_frontend = 1;
 
 	if (bind_conf->default_ctx)
-		err += ssl_sock_prepare_ctx(bind_conf, bind_conf->default_ctx);
+		err += ssl_sock_prepare_ctx(bind_conf, bind_conf->default_ssl_conf, bind_conf->default_ctx);
 
 	node = ebmb_first(&bind_conf->sni_ctx);
 	while (node) {
@@ -3249,7 +3373,7 @@
 		if (!sni->order && sni->ctx != bind_conf->default_ctx)
 			/* only initialize the CTX on its first occurrence and
 			   if it is not the default_ctx */
-			err += ssl_sock_prepare_ctx(bind_conf, sni->ctx);
+			err += ssl_sock_prepare_ctx(bind_conf, sni->conf, sni->ctx);
 		node = ebmb_next(node);
 	}
 
@@ -3259,7 +3383,7 @@
 		if (!sni->order && sni->ctx != bind_conf->default_ctx)
 			/* only initialize the CTX on its first occurrence and
 			   if it is not the default_ctx */
-			err += ssl_sock_prepare_ctx(bind_conf, sni->ctx);
+			err += ssl_sock_prepare_ctx(bind_conf, sni->conf, sni->ctx);
 		node = ebmb_next(node);
 	}
 	return err;
@@ -3330,8 +3454,12 @@
 		sni = ebmb_entry(node, struct sni_ctx, name);
 		back = ebmb_next(node);
 		ebmb_delete(node);
-		if (!sni->order) /* only free the CTX on its first occurrence */
+		if (!sni->order) { /* only free the CTX on its first occurrence */
 			SSL_CTX_free(sni->ctx);
+			ssl_sock_free_ssl_conf(sni->conf);
+			free(sni->conf);
+			sni->conf = NULL;
+		}
 		free(sni);
 		node = back;
 	}
@@ -3341,13 +3469,18 @@
 		sni = ebmb_entry(node, struct sni_ctx, name);
 		back = ebmb_next(node);
 		ebmb_delete(node);
-		if (!sni->order) /* only free the CTX on its first occurrence */
+		if (!sni->order) { /* only free the CTX on its first occurrence */
 			SSL_CTX_free(sni->ctx);
+			ssl_sock_free_ssl_conf(sni->conf);
+			free(sni->conf);
+			sni->conf = NULL;
+		}
 		free(sni);
 		node = back;
 	}
 
 	bind_conf->default_ctx = NULL;
+	bind_conf->default_ssl_conf = NULL;
 }
 
 /* Destroys all the contexts for a bind_conf. This is used during deinit(). */
@@ -3355,12 +3488,9 @@
 {
 	ssl_sock_free_ca(bind_conf);
 	ssl_sock_free_all_ctx(bind_conf);
-	free(bind_conf->ca_file);
+	ssl_sock_free_ssl_conf(&bind_conf->ssl_conf);
 	free(bind_conf->ca_sign_file);
 	free(bind_conf->ca_sign_pass);
-	free(bind_conf->ciphers);
-	free(bind_conf->ecdhe);
-	free(bind_conf->crl_file);
 	if (bind_conf->keys_ref) {
 		free(bind_conf->keys_ref->filename);
 		free(bind_conf->keys_ref->tlskeys);
@@ -3368,12 +3498,8 @@
 		free(bind_conf->keys_ref);
 	}
 	bind_conf->keys_ref = NULL;
-	bind_conf->crl_file = NULL;
-	bind_conf->ecdhe = NULL;
-	bind_conf->ciphers = NULL;
 	bind_conf->ca_sign_pass = NULL;
 	bind_conf->ca_sign_file = NULL;
-	bind_conf->ca_file = NULL;
 }
 
 /* Load CA cert file and private key used to generate certificates */
@@ -5249,7 +5375,7 @@
 }
 
 /* parse the "ca-file" bind keyword */
-static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	if (!*args[cur_arg + 1]) {
 		if (err)
@@ -5264,6 +5390,10 @@
 
 	return 0;
 }
+static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_ca_file(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "ca-sign-file" bind keyword */
 static int bind_parse_ca_sign_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
@@ -5295,7 +5425,7 @@
 }
 
 /* parse the "ciphers" bind keyword */
-static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	if (!*args[cur_arg + 1]) {
 		memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
@@ -5306,7 +5436,10 @@
 	conf->ciphers = strdup(args[cur_arg + 1]);
 	return 0;
 }
-
+static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, err);
+}
 /* parse the "crt" bind keyword */
 static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
@@ -5343,7 +5476,7 @@
 		return ERR_ALERT | ERR_FATAL;
 	}
 
-	if (ssl_sock_load_cert_list_file(args[cur_arg + 1], conf, err) > 0) {
+	if (ssl_sock_load_cert_list_file(args[cur_arg + 1], conf, px, err) > 0) {
 		memprintf(err, "'%s' : %s", args[cur_arg], *err);
 		return ERR_ALERT | ERR_FATAL;
 	}
@@ -5352,7 +5485,7 @@
 }
 
 /* parse the "crl-file" bind keyword */
-static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 #ifndef X509_V_FLAG_CRL_CHECK
 	if (err)
@@ -5373,9 +5506,13 @@
 	return 0;
 #endif
 }
+static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_crl_file(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "ecdhe" bind keyword keyword */
-static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 #if OPENSSL_VERSION_NUMBER < 0x0090800fL
 	if (err)
@@ -5397,6 +5534,10 @@
 	return 0;
 #endif
 }
+static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_ecdhe(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "crt-ignore-err" and "ca-ignore-err" bind keywords */
 static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
@@ -5437,21 +5578,29 @@
 }
 
 /* parse the "force-sslv3" bind keyword */
-static int bind_parse_force_sslv3(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_force_sslv3(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	conf->ssl_options |= BC_SSL_O_USE_SSLV3;
 	return 0;
 }
+static int bind_parse_force_sslv3(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_force_sslv3(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "force-tlsv10" bind keyword */
-static int bind_parse_force_tlsv10(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_force_tlsv10(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	conf->ssl_options |= BC_SSL_O_USE_TLSV10;
 	return 0;
 }
+static int bind_parse_force_tlsv10(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_force_tlsv10(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "force-tlsv11" bind keyword */
-static int bind_parse_force_tlsv11(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_force_tlsv11(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 #if SSL_OP_NO_TLSv1_1
 	conf->ssl_options |= BC_SSL_O_USE_TLSV11;
@@ -5462,9 +5611,13 @@
 	return ERR_ALERT | ERR_FATAL;
 #endif
 }
+static int bind_parse_force_tlsv11(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_force_tlsv11(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "force-tlsv12" bind keyword */
-static int bind_parse_force_tlsv12(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_force_tlsv12(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 #if SSL_OP_NO_TLSv1_2
 	conf->ssl_options |= BC_SSL_O_USE_TLSV12;
@@ -5475,46 +5628,68 @@
 	return ERR_ALERT | ERR_FATAL;
 #endif
 }
-
+static int bind_parse_force_tlsv12(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_force_tlsv12(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "no-tls-tickets" bind keyword */
-static int bind_parse_no_tls_tickets(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_no_tls_tickets(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	conf->ssl_options |= BC_SSL_O_NO_TLS_TICKETS;
 	return 0;
 }
-
+static int bind_parse_no_tls_tickets(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_no_tls_tickets(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "no-sslv3" bind keyword */
-static int bind_parse_no_sslv3(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_no_sslv3(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	conf->ssl_options |= BC_SSL_O_NO_SSLV3;
 	return 0;
 }
+static int bind_parse_no_sslv3(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_no_sslv3(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "no-tlsv10" bind keyword */
-static int bind_parse_no_tlsv10(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_no_tlsv10(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	conf->ssl_options |= BC_SSL_O_NO_TLSV10;
 	return 0;
 }
+static int bind_parse_no_tlsv10(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_no_tlsv10(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "no-tlsv11" bind keyword */
-static int bind_parse_no_tlsv11(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_no_tlsv11(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	conf->ssl_options |= BC_SSL_O_NO_TLSV11;
 	return 0;
 }
+static int bind_parse_no_tlsv11(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_no_tlsv11(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "no-tlsv12" bind keyword */
-static int bind_parse_no_tlsv12(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_no_tlsv12(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	conf->ssl_options |= BC_SSL_O_NO_TLSV12;
 	return 0;
 }
+static int bind_parse_no_tlsv12(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_no_tlsv12(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /* parse the "npn" bind keyword */
-static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 #ifdef OPENSSL_NPN_NEGOTIATED
 	char *p1, *p2;
@@ -5564,8 +5739,13 @@
 #endif
 }
 
+static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_npn(args, cur_arg, px, &conf->ssl_conf, err);
+}
+
 /* parse the "alpn" bind keyword */
-static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
 	char *p1, *p2;
@@ -5615,15 +5795,20 @@
 #endif
 }
 
+static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, err);
+}
+
 /* parse the "ssl" bind keyword */
 static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
 	conf->xprt = &ssl_sock;
 	conf->is_ssl = 1;
 
-	if (global_ssl.listen_default_ciphers && !conf->ciphers)
-		conf->ciphers = strdup(global_ssl.listen_default_ciphers);
-	conf->ssl_options |= global_ssl.listen_default_ssloptions;
+	if (global_ssl.listen_default_ciphers && !conf->ssl_conf.ciphers)
+		conf->ssl_conf.ciphers = strdup(global_ssl.listen_default_ciphers);
+	conf->ssl_conf.ssl_options |= global_ssl.listen_default_ssloptions;
 
 	return 0;
 }
@@ -5723,7 +5908,7 @@
 }
 
 /* parse the "verify" bind keyword */
-static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+static int ssl_bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
 {
 	if (!*args[cur_arg + 1]) {
 		if (err)
@@ -5746,6 +5931,10 @@
 
 	return 0;
 }
+static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+	return ssl_bind_parse_verify(args, cur_arg, px, &conf->ssl_conf, err);
+}
 
 /************** "server" keywords ****************/
 
@@ -6620,6 +6809,26 @@
  * the config parser can report an appropriate error when a known keyword was
  * not enabled.
  */
+static struct ssl_bind_kw ssl_bind_kws[] = {
+	{ "alpn",                  ssl_bind_parse_alpn,             1 }, /* set ALPN supported protocols */
+	{ "ca-file",               ssl_bind_parse_ca_file,          1 }, /* set CAfile to process verify on client cert */
+	{ "ciphers",               ssl_bind_parse_ciphers,          1 }, /* set SSL cipher suite */
+	{ "crl-file",              ssl_bind_parse_crl_file,         1 }, /* set certificat revocation list file use on client cert verify */
+	{ "ecdhe",                 ssl_bind_parse_ecdhe,            1 }, /* defines named curve for elliptic curve Diffie-Hellman */
+	{ "force-sslv3",           ssl_bind_parse_force_sslv3,      0 }, /* force SSLv3 */
+	{ "force-tlsv10",          ssl_bind_parse_force_tlsv10,     0 }, /* force TLSv10 */
+	{ "force-tlsv11",          ssl_bind_parse_force_tlsv11,     0 }, /* force TLSv11 */
+	{ "force-tlsv12",          ssl_bind_parse_force_tlsv12,     0 }, /* force TLSv12 */
+	{ "no-sslv3",              ssl_bind_parse_no_sslv3,         0 }, /* disable SSLv3 */
+	{ "no-tlsv10",             ssl_bind_parse_no_tlsv10,        0 }, /* disable TLSv10 */
+	{ "no-tlsv11",             ssl_bind_parse_no_tlsv11,        0 }, /* disable TLSv11 */
+	{ "no-tlsv12",             ssl_bind_parse_no_tlsv12,        0 }, /* disable TLSv12 */
+	{ "no-tls-tickets",        ssl_bind_parse_no_tls_tickets,   0 }, /* disable session resumption tickets */
+	{ "npn",                   ssl_bind_parse_npn,              1 }, /* set NPN supported protocols */
+	{ "verify",                ssl_bind_parse_verify,           1 }, /* set SSL verify method */
+	{ NULL, NULL, 0 },
+};
+
 static struct bind_kw_list bind_kws = { "SSL", { }, {
 	{ "alpn",                  bind_parse_alpn,            1 }, /* set ALPN supported protocols */
 	{ "ca-file",               bind_parse_ca_file,         1 }, /* set CAfile to process verify on client cert */