]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: Set verify 'required' as global default for servers side.
authorEmeric Brun <ebrun@exceliance.fr>
Wed, 29 Jan 2014 11:24:34 +0000 (12:24 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 29 Jan 2014 16:08:15 +0000 (17:08 +0100)
If no CA file specified on a server line, the config parser will show an error.

Adds an cmdline option '-dV' to re-set verify 'none' as global default on
servers side (previous behavior).

Also adds 'ssl-server-verify' global statement to set global default to
'none' or 'required'.

WARNING: this changes the default verify mode from "none" to "required" on
the server side, and it *will* break insecure setups.

doc/configuration.txt
include/types/global.h
src/cfgparse.c
src/haproxy.c
src/ssl_sock.c

index 88964c4693b9cb1b51b2eb783ac979bbf5f0c84f..141f12e975553ec010cf018ad10ce53be1f378dc 100644 (file)
@@ -455,6 +455,7 @@ The following keywords are supported in the "global" section :
    - ulimit-n
    - user
    - stats
+   - ssl-server-verify
    - node
    - description
    - unix-bind
@@ -625,6 +626,11 @@ stats bind-process [ all | odd | even | <number 1-32>[-<number 1-32>] ] ...
   warning will automatically be disabled when this setting is used, whatever
   the number of processes used.
 
+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
+  forced using cmdline option '-dV'.
+
 stats socket [<address:port>|<path>] [param*]
   Binds a UNIX socket to <path> or a TCPv4/v6 address to <address:port>.
   Connections to this socket will return various statistics outputs and even
@@ -8519,9 +8525,10 @@ track [<proxy>/]<server>
 
 verify [none|required]
   This setting is only available when support for OpenSSL was built in. If set
-  to 'none', server certificate is not verified. This is the default. In the
-  other case, The certificate provided by the server is verified using CAs from
-  'ca-file' and optional CRLs from 'crl-file'. On verify failure the handshake
+  to 'none', server certificate is not verified. In the other case, The
+  certificate provided by the server is verified using CAs from 'ca-file'
+  and optional CRLs from 'crl-file'. If 'ssl_server_verify' is not specified
+  in global  section, this is the default. On verify failure the handshake
   is aborted. It is critically important to verify server certificates when
   using SSL to connect to servers, otherwise the communication is prone to
   trivial man-in-the-middle attacks rendering SSL totally useless.
index 678d4fba500b4b98da8c9891b44d995ce526caac..3b010d80a47ec3ccd5f00edfc315699ca514eca8 100644 (file)
 #define ACCESS_LVL_OPER     2
 #define ACCESS_LVL_ADMIN    3
 
+/* SSL server verify mode */
+enum {
+       SSL_SERVER_VERIFY_NONE = 0,
+       SSL_SERVER_VERIFY_REQUIRED = 1,
+};
+
 /* FIXME : this will have to be redefined correctly */
 struct global {
 #ifdef USE_OPENSSL
@@ -79,6 +85,7 @@ struct global {
        char *listen_default_ciphers;
        char *connect_default_ciphers;
 #endif
+       unsigned int ssl_server_verify; /* default verify mode on servers side */
        struct freq_ctr conn_per_sec;
        struct freq_ctr sess_per_sec;
        struct freq_ctr ssl_per_sec;
index 4d1ecd02a495cc440e28b432622e07788be6d617..c7a491ff8ae27ca393c48fee87b4b7eb414f40d3 100644 (file)
@@ -862,6 +862,22 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                goto out;
 #endif
        }
+       else if (!strcmp(args[0], "ssl-server-verify")) {
+               if (*(args[1]) == 0) {
+                       Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+               if (strcmp(args[1],"none") == 0)
+                       global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
+               else if (strcmp(args[1],"required") == 0)
+                       global.ssl_server_verify = SSL_SERVER_VERIFY_REQUIRED;
+               else {
+                       Alert("parsing [%s:%d] : '%s' expects 'none' or 'required' as argument.\n", file, linenum, args[0]);
+                       err_code |= ERR_ALERT | ERR_FATAL;
+                       goto out;
+               }
+       }
        else if (!strcmp(args[0], "maxconnrate")) {
                if (global.cps_lim != 0) {
                        Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
index fd6006dc4a6df5593312e37b08b330da6b296751..442d16a871ddb59e609dccd6ab252ffd3020e7cd 100644 (file)
@@ -128,6 +128,7 @@ struct global global = {
        .maxzlibmem = 0,
 #endif
        .comp_rate_lim = 0,
+       .ssl_server_verify = SSL_SERVER_VERIFY_REQUIRED,
        .unix_bind = {
                 .ux = {
                         .uid = -1,
@@ -383,6 +384,7 @@ void usage(char *name)
 #if defined(CONFIG_HAP_LINUX_SPLICE)
                "        -dS disables splice usage (broken on old kernels)\n"
 #endif
+               "        -dV disables SSL verify on servers side\n"
                "        -sf/-st [pid ]* finishes/terminates old pids. Must be last arguments.\n"
                "\n",
                name, DEFAULT_MAXCONN, cfg_maxpconn);
@@ -587,6 +589,8 @@ void init(int argc, char **argv)
                        else if (*flag == 'd' && flag[1] == 'S')
                                global.tune.options &= ~GTUNE_USE_SPLICE;
 #endif
+                       else if (*flag == 'd' && flag[1] == 'V')
+                               global.ssl_server_verify = SSL_SERVER_VERIFY_NONE;
                        else if (*flag == 'V')
                                arg_mode |= MODE_VERBOSE;
                        else if (*flag == 'd' && flag[1] == 'b')
index 88c758b1dff552644eae25c133760bec74bc787a..45a6dd03e9c6d06ea9afee27628b022899245068 100644 (file)
 #define SSL_SOCK_ST_TO_CAEDEPTH(s) ((s >> (6+16)) & 15)
 #define SSL_SOCK_ST_TO_CRTERROR(s) ((s >> (4+6+16)) & 63)
 
+/* server and bind verify method, it uses a global value as default */
+enum {
+       SSL_SOCK_VERIFY_DEFAULT  = 0,
+       SSL_SOCK_VERIFY_REQUIRED = 1,
+       SSL_SOCK_VERIFY_OPTIONAL = 2,
+       SSL_SOCK_VERIFY_NONE     = 3,
+};
+
 int sslconns = 0;
 int totalsslconns = 0;
 
@@ -651,6 +659,7 @@ int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, struct
 int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy *curproxy)
 {
        int cfgerr = 0;
+       int verify = SSL_VERIFY_NONE;
        int ssloptions =
                SSL_OP_ALL | /* all known workarounds for bugs */
                SSL_OP_NO_SSLv2 |
@@ -695,8 +704,19 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy
 
        SSL_CTX_set_options(ctx, ssloptions);
        SSL_CTX_set_mode(ctx, sslmode);
-       SSL_CTX_set_verify(ctx, bind_conf->verify ? bind_conf->verify : SSL_VERIFY_NONE, ssl_sock_bind_verifycbk);
-       if (bind_conf->verify & SSL_VERIFY_PEER) {
+       switch (bind_conf->verify) {
+               case SSL_SOCK_VERIFY_NONE:
+                       verify = SSL_VERIFY_NONE;
+                       break;
+               case SSL_SOCK_VERIFY_OPTIONAL:
+                       verify = SSL_VERIFY_PEER;
+                       break;
+               case SSL_SOCK_VERIFY_REQUIRED:
+                       verify = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+                       break;
+       }
+       SSL_CTX_set_verify(ctx, verify, ssl_sock_bind_verifycbk);
+       if (verify & SSL_VERIFY_PEER) {
                if (bind_conf->ca_file) {
                        /* load CAfile to verify */
                        if (!SSL_CTX_load_verify_locations(ctx, bind_conf->ca_file, NULL)) {
@@ -707,6 +727,11 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy
                        /* 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));
                }
+               else {
+                       Alert("Proxy '%s': verify is enabled but no CA file specified for bind '%s' at [%s:%d].\n",
+                             curproxy->id, bind_conf->arg, bind_conf->file, bind_conf->line);
+                       cfgerr++;
+               }
 #ifdef X509_V_FLAG_CRL_CHECK
                if (bind_conf->crl_file) {
                        X509_STORE *store = SSL_CTX_get_cert_store(ctx);
@@ -906,6 +931,7 @@ int ssl_sock_prepare_srv_ctx(struct server *srv, struct proxy *curproxy)
                SSL_MODE_ENABLE_PARTIAL_WRITE |
                SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
                SSL_MODE_RELEASE_BUFFERS;
+       int verify = SSL_VERIFY_NONE;
 
        /* Make sure openssl opens /dev/urandom before the chroot */
        if (!ssl_initialize_random()) {
@@ -974,10 +1000,22 @@ int ssl_sock_prepare_srv_ctx(struct server *srv, struct proxy *curproxy)
 
        SSL_CTX_set_options(srv->ssl_ctx.ctx, options);
        SSL_CTX_set_mode(srv->ssl_ctx.ctx, mode);
+
+       if (global.ssl_server_verify == SSL_SERVER_VERIFY_REQUIRED)
+               verify = SSL_VERIFY_PEER;
+
+       switch (srv->ssl_ctx.verify) {
+               case SSL_SOCK_VERIFY_NONE:
+                       verify = SSL_VERIFY_NONE;
+                       break;
+               case SSL_SOCK_VERIFY_REQUIRED:
+                       verify = SSL_VERIFY_PEER;
+                       break;
+       }
        SSL_CTX_set_verify(srv->ssl_ctx.ctx,
-                          srv->ssl_ctx.verify ? srv->ssl_ctx.verify : SSL_VERIFY_NONE,
+                          verify,
                           srv->ssl_ctx.verify_host ? ssl_sock_srv_verifycbk : NULL);
-       if (srv->ssl_ctx.verify & SSL_VERIFY_PEER) {
+       if (verify & SSL_VERIFY_PEER) {
                if (srv->ssl_ctx.ca_file) {
                        /* load CAfile to verify */
                        if (!SSL_CTX_load_verify_locations(srv->ssl_ctx.ctx, srv->ssl_ctx.ca_file, NULL)) {
@@ -987,6 +1025,17 @@ int ssl_sock_prepare_srv_ctx(struct server *srv, struct proxy *curproxy)
                                cfgerr++;
                        }
                }
+               else {
+                       if (global.ssl_server_verify == SSL_SERVER_VERIFY_REQUIRED)
+                               Alert("Proxy '%s', server '%s' |%s:%d] verify is enabled by default but no CA file specified. If you're running on a LAN where you're certain to trust the server's certificate, please set an explicit 'verify none' statement on the 'server' line, or use 'ssl-server-verify none' in the global section to disable server-side verifications by default.\n",
+                                     curproxy->id, srv->id,
+                                     srv->conf.file, srv->conf.line);
+                       else
+                               Alert("Proxy '%s', server '%s' |%s:%d] verify is enabled but no CA file specified.\n",
+                                     curproxy->id, srv->id,
+                                     srv->conf.file, srv->conf.line);
+                       cfgerr++;
+               }
 #ifdef X509_V_FLAG_CRL_CHECK
                if (srv->ssl_ctx.crl_file) {
                        X509_STORE *store = SSL_CTX_get_cert_store(srv->ssl_ctx.ctx);
@@ -3190,11 +3239,11 @@ static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct
        }
 
        if (strcmp(args[cur_arg + 1], "none") == 0)
-               conf->verify = SSL_VERIFY_NONE;
+               conf->verify = SSL_SOCK_VERIFY_NONE;
        else if (strcmp(args[cur_arg + 1], "optional") == 0)
-               conf->verify = SSL_VERIFY_PEER;
+               conf->verify = SSL_SOCK_VERIFY_OPTIONAL;
        else if (strcmp(args[cur_arg + 1], "required") == 0)
-               conf->verify = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+               conf->verify = SSL_SOCK_VERIFY_REQUIRED;
        else {
                if (err)
                        memprintf(err, "'%s' : unknown verify method '%s', only 'none', 'optional', and 'required' are supported\n",
@@ -3380,9 +3429,9 @@ static int srv_parse_verify(char **args, int *cur_arg, struct proxy *px, struct
        }
 
        if (strcmp(args[*cur_arg + 1], "none") == 0)
-               newsrv->ssl_ctx.verify = SSL_VERIFY_NONE;
+               newsrv->ssl_ctx.verify = SSL_SOCK_VERIFY_NONE;
        else if (strcmp(args[*cur_arg + 1], "required") == 0)
-               newsrv->ssl_ctx.verify = SSL_VERIFY_PEER;
+               newsrv->ssl_ctx.verify = SSL_SOCK_VERIFY_REQUIRED;
        else {
                if (err)
                        memprintf(err, "'%s' : unknown verify method '%s', only 'none' and 'required' are supported\n",