From c1cae82b80a7b7f2ee8944f8aca6407cd982b524 Mon Sep 17 00:00:00 2001
From: Emeric Brun <ebrun@haproxy.com>
Date: Thu, 30 Oct 2014 15:56:50 +0100
Subject: [PATCH 02/13] MINOR: ssl: add statement to force some ssl options in
 global.

Adds global statements 'ssl-default-server-options' and
'ssl-default-bind-options' to force on 'server' and 'bind' lines
some ssl options.

Currently available options are 'no-sslv3', 'no-tlsv10', 'no-tlsv11',
'no-tlsv12', 'force-sslv3', 'force-tlsv10', 'force-tlsv11',
'force-tlsv12', and 'no-tls-tickets'.

Example:
      global
        ssl-default-server-options no-sslv3
        ssl-default-bind-options no-sslv3
(cherry picked from commit 2c86cbf7539af2008d61780b14f37ea8c46c2192)
---
 doc/configuration.txt  |  77 ++++++++++++++++++++++++----------
 include/types/global.h |   2 +
 src/ssl_sock.c         | 112 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 168 insertions(+), 23 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 88e25f0..a1b3458 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -657,6 +657,15 @@ ssl-default-bind-ciphers <ciphers>
   as "AES:ALL:!aNULL:!eNULL:+RC4:@STRENGTH" (without quotes). Please check the
   "bind" keyword for more information.
 
+ssl-default-bind-options [<option>]...
+  This setting is only available when support for OpenSSL was built in. It sets
+  default ssl-options to force on all "bind" lines. Please check the "bind"
+  keyword to see available options.
+
+  Example:
+        global
+           ssl-default-bind-options no-sslv3 no-tls-tickets
+
 ssl-default-server-ciphers <ciphers>
   This setting is only available when support for OpenSSL was built in. It
   sets the default string describing the list of cipher algorithms that are
@@ -665,6 +674,11 @@ ssl-default-server-ciphers <ciphers>
   defined in "man 1 ciphers". Please check the "server" keyword for more
   information.
 
+ssl-default-server-options [<option>]...
+  This setting is only available when support for OpenSSL was built in. It sets
+  default ssl-options to force on all "server" lines. Please check the "server"
+  keyword to see available options.
+
 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
@@ -8375,19 +8389,23 @@ defer-accept
 force-sslv3
   This option enforces use of SSLv3 only on SSL connections instantiated from
   this listener. SSLv3 is generally less expensive than the TLS counterparts
-  for high connection rates. See also "force-tls*", "no-sslv3", and "no-tls*".
+  for high connection rates. This option is also available on global statement
+  "ssl-default-bind-options". See also "no-tlsv*" and "no-sslv3".
 
 force-tlsv10
   This option enforces use of TLSv1.0 only on SSL connections instantiated from
-  this listener. See also "force-tls*", "no-sslv3", and "no-tls*".
+  this listener. This option is also available on global statement
+  "ssl-default-bind-options". See also "no-tlsv*" and "no-sslv3".
 
 force-tlsv11
   This option enforces use of TLSv1.1 only on SSL connections instantiated from
-  this listener. See also "force-tls*", "no-sslv3", and "no-tls*".
+  this listener. This option is also available on global statement
+  "ssl-default-bind-options". See also "no-tlsv*", and "no-sslv3".
 
 force-tlsv12
   This option enforces use of TLSv1.2 only on SSL connections instantiated from
-  this listener. See also "force-tls*", "no-sslv3", and "no-tls*".
+  this listener. This option is also available on global statement
+  "ssl-default-bind-options". See also "no-tlsv*", and "no-sslv3".
 
 gid <gid>
   Sets the group of the UNIX sockets to the designated system gid. It can also
@@ -8480,35 +8498,40 @@ no-sslv3
   This setting is only available when support for OpenSSL was built in. It
   disables support for SSLv3 on any sockets instantiated from the listener when
   SSL is supported. Note that SSLv2 is forced disabled in the code and cannot
-  be enabled using any configuration option. See also "force-tls*",
+  be enabled using any configuration option. This option is also available on
+  global statement "ssl-default-bind-options". See also "force-tls*",
   and "force-sslv3".
 
 no-tls-tickets
   This setting is only available when support for OpenSSL was built in. It
   disables the stateless session resumption (RFC 5077 TLS Ticket
   extension) and force to use stateful session resumption. Stateless
-  session resumption is more expensive in CPU usage.
+  session resumption is more expensive in CPU usage. This option is also
+  available on global statement "ssl-default-bind-options".
 
 no-tlsv10
   This setting is only available when support for OpenSSL was built in. It
   disables support for TLSv1.0 on any sockets instantiated from the listener
   when SSL is supported. Note that SSLv2 is forced disabled in the code and
-  cannot be enabled using any configuration option. See also "force-tls*",
-  and "force-sslv3".
+  cannot be enabled using any configuration option. This option is also
+  available on global statement "ssl-default-bind-options". See also
+  "force-tlsv*", and "force-sslv3".
 
 no-tlsv11
   This setting is only available when support for OpenSSL was built in. It
   disables support for TLSv1.1 on any sockets instantiated from the listener
   when SSL is supported. Note that SSLv2 is forced disabled in the code and
-  cannot be enabled using any configuration option. See also "force-tls*",
-  and "force-sslv3".
+  cannot be enabled using any configuration option. This option is also
+  available on global statement "ssl-default-bind-options". See also
+  "force-tlsv*", and "force-sslv3".
 
 no-tlsv12
   This setting is only available when support for OpenSSL was built in. It
   disables support for TLSv1.2 on any sockets instantiated from the listener
   when SSL is supported. Note that SSLv2 is forced disabled in the code and
-  cannot be enabled using any configuration option. See also "force-tls*",
-  and "force-sslv3".
+  cannot be enabled using any configuration option. This option is also
+  available on global statement "ssl-default-bind-options". See also
+  "force-tlsv*", and "force-sslv3".
 
 npn <protocols>
   This enables the NPN TLS extension and advertises the specified protocol list
@@ -8839,25 +8862,29 @@ fall <count>
 force-sslv3
   This option enforces use of SSLv3 only when SSL is used to communicate with
   the server. SSLv3 is generally less expensive than the TLS counterparts for
-  high connection rates. See also "no-tlsv*", "no-sslv3".
+  high connection rates. This option is also available on global statement
+  "ssl-default-server-options". See also "no-tlsv*", "no-sslv3".
 
   Supported in default-server: No
 
 force-tlsv10
   This option enforces use of TLSv1.0 only when SSL is used to communicate with
-  the server. See also "no-tlsv*", "no-sslv3".
+  the server. This option is also available on global statement
+  "ssl-default-server-options". See also "no-tlsv*", "no-sslv3".
 
   Supported in default-server: No
 
 force-tlsv11
   This option enforces use of TLSv1.1 only when SSL is used to communicate with
-  the server. See also "no-tlsv*", "no-sslv3".
+  the server. This option is also available on global statement
+  "ssl-default-server-options". See also "no-tlsv*", "no-sslv3".
 
   Supported in default-server: No
 
 force-tlsv12
   This option enforces use of TLSv1.2 only when SSL is used to communicate with
-  the server. See also "no-tlsv*", "no-sslv3".
+  the server. This option is also available on global statement
+  "ssl-default-server-options". See also "no-tlsv*", "no-sslv3".
 
   Supported in default-server: No
 
@@ -8945,7 +8972,8 @@ no-tls-tickets
   This setting is only available when support for OpenSSL was built in. It
   disables the stateless session resumption (RFC 5077 TLS Ticket
   extension) and force to use stateful session resumption. Stateless
-  session resumption is more expensive in CPU usage for servers.
+  session resumption is more expensive in CPU usage for servers. This option
+  is also available on global statement "ssl-default-server-options".
 
   Supported in default-server: No
 
@@ -8953,8 +8981,9 @@ no-tlsv10
   This option disables support for TLSv1.0 when SSL is used to communicate with
   the server. Note that SSLv2 is disabled in the code and cannot be enabled
   using any configuration option. TLSv1 is more expensive than SSLv3 so it
-  often makes sense to disable it when communicating with local servers. See
-  also "force-sslv3", "force-tlsv*".
+  often makes sense to disable it when communicating with local servers. This
+  option is also available on global statement "ssl-default-server-options".
+  See also "force-sslv3", "force-tlsv*".
 
   Supported in default-server: No
 
@@ -8962,8 +8991,9 @@ no-tlsv11
   This option disables support for TLSv1.1 when SSL is used to communicate with
   the server. Note that SSLv2 is disabled in the code and cannot be enabled
   using any configuration option. TLSv1 is more expensive than SSLv3 so it
-  often makes sense to disable it when communicating with local servers. See
-  also "force-sslv3", "force-tlsv*".
+  often makes sense to disable it when communicating with local servers. This
+  option is also available on global statement "ssl-default-server-options".
+  See also "force-sslv3", "force-tlsv*".
 
   Supported in default-server: No
 
@@ -8971,8 +9001,9 @@ no-tlsv12
   This option disables support for TLSv1.2 when SSL is used to communicate with
   the server. Note that SSLv2 is disabled in the code and cannot be enabled
   using any configuration option. TLSv1 is more expensive than SSLv3 so it
-  often makes sense to disable it when communicating with local servers. See
-  also "force-sslv3", "force-tlsv*".
+  often makes sense to disable it when communicating with local servers. This
+  option is also available on global statement "ssl-default-server-options".
+  See also "force-sslv3", "force-tlsv*".
 
   Supported in default-server: No
 
diff --git a/include/types/global.h b/include/types/global.h
index 77df1dd..f1525ae 100644
--- a/include/types/global.h
+++ b/include/types/global.h
@@ -85,6 +85,8 @@ struct global {
 	int maxsslconn;
 	char *listen_default_ciphers;
 	char *connect_default_ciphers;
+	int listen_default_ssloptions;
+	int connect_default_ssloptions;
 #endif
 	unsigned int ssl_server_verify; /* default verify mode on servers side */
 	struct freq_ctr conn_per_sec;
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 938e534..f1616ca 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -56,6 +56,7 @@
 #include <common/standard.h>
 #include <common/ticks.h>
 #include <common/time.h>
+#include <common/cfgparse.h>
 
 #include <ebsttree.h>
 
@@ -4109,6 +4110,7 @@ static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bin
 
 	if (global.listen_default_ciphers && !conf->ciphers)
 		conf->ciphers = strdup(global.listen_default_ciphers);
+	conf->ssl_options |= global.listen_default_ssloptions;
 
 	list_for_each_entry(l, &conf->listeners, by_bind)
 		l->xprt = &ssl_sock;
@@ -4173,6 +4175,7 @@ static int srv_parse_check_ssl(char **args, int *cur_arg, struct proxy *px, stru
 	newsrv->check.use_ssl = 1;
 	if (global.connect_default_ciphers && !newsrv->ssl_ctx.ciphers)
 		newsrv->ssl_ctx.ciphers = strdup(global.connect_default_ciphers);
+	newsrv->ssl_ctx.options |= global.connect_default_ssloptions;
 	return 0;
 }
 
@@ -4366,6 +4369,106 @@ static int srv_parse_verifyhost(char **args, int *cur_arg, struct proxy *px, str
 	return 0;
 }
 
+/* parse the "ssl-default-bind-options" keyword in global section */
+static int ssl_parse_default_bind_options(char **args, int section_type, struct proxy *curpx,
+                                          struct proxy *defpx, const char *file, int line,
+                                          char **err) {
+	int i = 1;
+
+	if (*(args[i]) == 0) {
+		memprintf(err, "global statement '%s' expects an option as an argument.", args[0]);
+		return -1;
+	}
+	while (*(args[i])) {
+		if (!strcmp(args[i], "no-sslv3"))
+			global.listen_default_ssloptions |= BC_SSL_O_NO_SSLV3;
+		else if (!strcmp(args[i], "no-tlsv10"))
+			global.listen_default_ssloptions |= BC_SSL_O_NO_TLSV10;
+		else if (!strcmp(args[i], "no-tlsv11"))
+			global.listen_default_ssloptions |= BC_SSL_O_NO_TLSV11;
+		else if (!strcmp(args[i], "no-tlsv12"))
+			global.listen_default_ssloptions |= BC_SSL_O_NO_TLSV12;
+		else if (!strcmp(args[i], "force-sslv3"))
+			global.listen_default_ssloptions |= BC_SSL_O_USE_SSLV3;
+		else if (!strcmp(args[i], "force-tlsv10"))
+			global.listen_default_ssloptions |= BC_SSL_O_USE_TLSV10;
+		else if (!strcmp(args[i], "force-tlsv11")) {
+#if SSL_OP_NO_TLSv1_1
+			global.listen_default_ssloptions |= BC_SSL_O_USE_TLSV11;
+#else
+			memprintf(err, "'%s' '%s': library does not support protocol TLSv1.1", args[0], args[i]);
+			return -1;
+#endif
+		}
+		else if (!strcmp(args[i], "force-tlsv12")) {
+#if SSL_OP_NO_TLSv1_2
+			global.listen_default_ssloptions |= BC_SSL_O_USE_TLSV12;
+#else
+			memprintf(err, "'%s' '%s': library does not support protocol TLSv1.2", args[0], args[i]);
+			return -1;
+#endif
+		}
+		else if (!strcmp(args[i], "no-tls-tickets"))
+			global.listen_default_ssloptions |= BC_SSL_O_NO_TLS_TICKETS;
+		else {
+			memprintf(err, "unknown option '%s' on global statement '%s'.", args[i], args[0]);
+			return -1;
+		}
+		i++;
+	}
+	return 0;
+}
+
+/* parse the "ssl-default-server-options" keyword in global section */
+static int ssl_parse_default_server_options(char **args, int section_type, struct proxy *curpx,
+                                            struct proxy *defpx, const char *file, int line,
+                                            char **err) {
+	int i = 1;
+
+	if (*(args[i]) == 0) {
+		memprintf(err, "global statement '%s' expects an option as an argument.", args[0]);
+		return -1;
+	}
+	while (*(args[i])) {
+		if (!strcmp(args[i], "no-sslv3"))
+			global.connect_default_ssloptions |= SRV_SSL_O_NO_SSLV3;
+		else if (!strcmp(args[i], "no-tlsv10"))
+			global.connect_default_ssloptions |= SRV_SSL_O_NO_TLSV10;
+		else if (!strcmp(args[i], "no-tlsv11"))
+			global.connect_default_ssloptions |= SRV_SSL_O_NO_TLSV11;
+		else if (!strcmp(args[i], "no-tlsv12"))
+			global.connect_default_ssloptions |= SRV_SSL_O_NO_TLSV12;
+		else if (!strcmp(args[i], "force-sslv3"))
+			global.connect_default_ssloptions |= SRV_SSL_O_USE_SSLV3;
+		else if (!strcmp(args[i], "force-tlsv10"))
+			global.connect_default_ssloptions |= SRV_SSL_O_USE_TLSV10;
+		else if (!strcmp(args[i], "force-tlsv11")) {
+#if SSL_OP_NO_TLSv1_1
+			global.connect_default_ssloptions |= SRV_SSL_O_USE_TLSV11;
+#else
+			memprintf(err, "'%s' '%s': library does not support protocol TLSv1.1", args[0], args[i]);
+			return -1;
+#endif
+		}
+		else if (!strcmp(args[i], "force-tlsv12")) {
+#if SSL_OP_NO_TLSv1_2
+			global.connect_default_ssloptions |= SRV_SSL_O_USE_TLSV12;
+#else
+			memprintf(err, "'%s' '%s': library does not support protocol TLSv1.2", args[0], args[i]);
+			return -1;
+#endif
+		}
+		else if (!strcmp(args[i], "no-tls-tickets"))
+			global.connect_default_ssloptions |= SRV_SSL_O_NO_TLS_TICKETS;
+		else {
+			memprintf(err, "unknown option '%s' on global statement '%s'.", args[i], args[0]);
+			return -1;
+		}
+		i++;
+	}
+	return 0;
+}
+
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted.
  */
@@ -4493,6 +4596,12 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
 	{ NULL, NULL, 0, 0 },
 }};
 
+static struct cfg_kw_list cfg_kws = {ILH, {
+	{ CFG_GLOBAL, "ssl-default-bind-options", ssl_parse_default_bind_options },
+	{ CFG_GLOBAL, "ssl-default-server-options", ssl_parse_default_server_options },
+	{ 0, NULL, NULL },
+}};
+
 /* transport-layer operations for SSL sockets */
 struct xprt_ops ssl_sock = {
 	.snd_buf  = ssl_sock_from_buf,
@@ -4520,6 +4629,8 @@ static void __ssl_sock_init(void)
 		global.listen_default_ciphers = strdup(global.listen_default_ciphers);
 	if (global.connect_default_ciphers)
 		global.connect_default_ciphers = strdup(global.connect_default_ciphers);
+	global.listen_default_ssloptions = BC_SSL_O_NONE;
+	global.connect_default_ssloptions = SRV_SSL_O_NONE;
 
 	SSL_library_init();
 	cm = SSL_COMP_get_compression_methods();
@@ -4528,6 +4639,7 @@ static void __ssl_sock_init(void)
 	acl_register_keywords(&acl_kws);
 	bind_register_keywords(&bind_kws);
 	srv_register_keywords(&srv_kws);
+	cfg_register_keywords(&cfg_kws);
 }
 
 /*
-- 
2.1.4

