]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl: add statements 'verify', 'ca-file' and 'crl-file' on servers.
authorEmeric Brun <ebrun@exceliance.fr>
Thu, 11 Oct 2012 14:11:36 +0000 (16:11 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 12 Oct 2012 10:05:15 +0000 (12:05 +0200)
It now becomes possible to verify the server's certificate using the "verify"
directive. This one only supports "none" and "required", as it does not make
much sense to also support "optional" here.

doc/configuration.txt
include/types/server.h
src/ssl_sock.c

index d9a756fdbe877bd80a63f62242360232afd81f25..598d5d2eb5f6792276245a349848a41909c16a99 100644 (file)
@@ -7048,6 +7048,13 @@ backup
 
   Supported in default-server: No
 
+ca-file <cafile>
+  This setting is only available when support for OpenSSL was built in. It
+  designates a PEM file from which to load CA certificates used to verify
+  server's certificate.
+
+  Supported in default-server: No
+
 check
   This option enables health checks on the server. By default, a server is
   always considered available. If "check" is set, the server is available when
@@ -7110,6 +7117,13 @@ cookie <value>
 
   Supported in default-server: No
 
+crl-file <crlfile>
+  This setting is only available when support for OpenSSL was built in. It
+  designates a PEM file from which to load certificate revocation list used
+  to verify server's certificate.
+
+  Supported in default-server: No
+
 disabled
   The "disabled" keyword starts the server in the "disabled" state. That means
   that it is marked down in maintenance mode, and no connection other than the
@@ -7456,6 +7470,15 @@ track [<proxy>/]<server>
 
   Supported in default-server: No
 
+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
+  is aborted.
+
+  Supported in default-server: No
+
 weight <weight>
   The "weight" parameter is used to adjust the server's weight relative to
   other servers. All servers will receive a load proportional to their weight
index 2d2bb87e0636b826b96d4ce0af7e34b10180037b..1a69f83d1cb01d4f07166e6987353ee359bf45c8 100644 (file)
@@ -197,6 +197,9 @@ struct server {
                SSL_SESSION *reused_sess;
                char *ciphers;                  /* cipher suite to use if non-null */
                int options;                    /* ssl options */
+               int verify;                     /* verify method (set of SSL_VERIFY_* flags) */
+               char *ca_file;                  /* CAfile to use on verify */
+               char *crl_file;                 /* CRLfile to use on verify */
        } ssl_ctx;
 #endif
        struct {
index fb59515af6a87dba643aac5bbc660d98d9571355..6c9eae4fe6b0c795e08d57a6e9b31ce23303b641 100644 (file)
@@ -628,7 +628,34 @@ 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);
-       SSL_CTX_set_verify(srv->ssl_ctx.ctx, SSL_VERIFY_NONE, NULL);
+       SSL_CTX_set_verify(srv->ssl_ctx.ctx, srv->ssl_ctx.verify ? srv->ssl_ctx.verify : SSL_VERIFY_NONE, NULL);
+       if (srv->ssl_ctx.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)) {
+                               Alert("Proxy '%s', server '%s' |%s:%d] unable to load CA file '%s'.\n",
+                                     curproxy->id, srv->id,
+                                     srv->conf.file, srv->conf.line, srv->ssl_ctx.ca_file);
+                               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);
+
+                       if (!store || !X509_STORE_load_locations(store, srv->ssl_ctx.crl_file, NULL)) {
+                               Alert("Proxy '%s', server '%s' |%s:%d] unable to configure CRL file '%s'.\n",
+                                     curproxy->id, srv->id,
+                                     srv->conf.file, srv->conf.line, srv->ssl_ctx.crl_file);
+                               cfgerr++;
+                       }
+                       else {
+                               X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+                       }
+               }
+#endif
+       }
+
        SSL_CTX_set_session_cache_mode(srv->ssl_ctx.ctx, SSL_SESS_CACHE_OFF);
        if (srv->ssl_ctx.ciphers &&
                !SSL_CTX_set_cipher_list(srv->ssl_ctx.ctx, srv->ssl_ctx.ciphers)) {
@@ -1189,14 +1216,11 @@ static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct
                return ERR_ALERT | ERR_FATAL;
        }
 
-       if ((*args[cur_arg + 1] != '/') && global.ca_base) {
-               conf->ca_file = malloc(strlen(global.ca_base) + 1 + strlen(args[cur_arg + 1]) + 1);
-               if (conf->ca_file)
-                       sprintf(conf->ca_file, "%s/%s", global.ca_base, args[cur_arg + 1]);
-               return 0;
-       }
+       if ((*args[cur_arg + 1] != '/') && global.ca_base)
+               memprintf(&conf->ca_file, "%s/%s", global.ca_base, args[cur_arg + 1]);
+       else
+               memprintf(&conf->ca_file, "%s", args[cur_arg + 1]);
 
-       conf->ca_file = strdup(args[cur_arg + 1]);
        return 0;
 }
 
@@ -1254,14 +1278,11 @@ static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struc
                return ERR_ALERT | ERR_FATAL;
        }
 
-       if ((*args[cur_arg + 1] != '/') && global.ca_base) {
-               conf->crl_file = malloc(strlen(global.ca_base) + 1 + strlen(args[cur_arg + 1]) + 1);
-               if (conf->crl_file)
-                       sprintf(conf->crl_file, "%s/%s", global.ca_base, args[cur_arg + 1]);
-               return 0;
-       }
+       if ((*args[cur_arg + 1] != '/') && global.ca_base)
+               memprintf(&conf->crl_file, "%s/%s", global.ca_base, args[cur_arg + 1]);
+       else
+               memprintf(&conf->crl_file, "%s", args[cur_arg + 1]);
 
-       conf->crl_file = strdup(args[cur_arg + 1]);
        return 0;
 #endif
 }
@@ -1448,6 +1469,23 @@ static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct
 
 /************** "server" keywords ****************/
 
+/* parse the "ca-file" server keyword */
+static int srv_parse_ca_file(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
+{
+       if (!*args[*cur_arg + 1]) {
+               if (err)
+                       memprintf(err, "'%s' : missing CAfile path", args[*cur_arg]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       if ((*args[*cur_arg + 1] != '/') && global.ca_base)
+               memprintf(&newsrv->ssl_ctx.ca_file, "%s/%s", global.ca_base, args[*cur_arg + 1]);
+       else
+               memprintf(&newsrv->ssl_ctx.ca_file, "%s", args[*cur_arg + 1]);
+
+       return 0;
+}
+
 /* parse the "check-ssl" server keyword */
 static int srv_parse_check_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
 {
@@ -1470,6 +1508,30 @@ static int srv_parse_ciphers(char **args, int *cur_arg, struct proxy *px, struct
        return 0;
 }
 
+/* parse the "crl-file" server keyword */
+static int srv_parse_crl_file(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
+{
+#ifndef X509_V_FLAG_CRL_CHECK
+       if (err)
+               memprintf(err, "'%s' : library does not support CRL verify", args[*cur_arg]);
+       return ERR_ALERT | ERR_FATAL;
+#else
+       if (!*args[*cur_arg + 1]) {
+               if (err)
+                       memprintf(err, "'%s' : missing CRLfile path", args[*cur_arg]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       if ((*args[*cur_arg + 1] != '/') && global.ca_base)
+               memprintf(&newsrv->ssl_ctx.crl_file, "%s/%s", global.ca_base, args[*cur_arg + 1]);
+       else
+               memprintf(&newsrv->ssl_ctx.crl_file, "%s", args[*cur_arg + 1]);
+
+       return 0;
+#endif
+}
+
+
 /* parse the "force-sslv3" server keyword */
 static int srv_parse_force_sslv3(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
 {
@@ -1554,6 +1616,29 @@ static int srv_parse_ssl(char **args, int *cur_arg, struct proxy *px, struct ser
        return 0;
 }
 
+/* parse the "verify" server keyword */
+static int srv_parse_verify(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
+{
+       if (!*args[*cur_arg + 1]) {
+               if (err)
+                       memprintf(err, "'%s' : missing verify method", args[*cur_arg]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       if (strcmp(args[*cur_arg + 1], "none") == 0)
+               newsrv->ssl_ctx.verify = SSL_VERIFY_NONE;
+       else if (strcmp(args[*cur_arg + 1], "required") == 0)
+               newsrv->ssl_ctx.verify = SSL_VERIFY_PEER;
+       else {
+               if (err)
+                       memprintf(err, "'%s' : unknown verify method '%s', only 'none' and 'required' are supported\n",
+                                 args[*cur_arg], args[*cur_arg + 1]);
+               return ERR_ALERT | ERR_FATAL;
+       }
+
+       return 0;
+}
+
 /* Note: must not be declared <const> as its list will be overwritten.
  * Please take care of keeping this list alphabetically sorted.
  */
@@ -1623,8 +1708,10 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
  * not enabled.
  */
 static struct srv_kw_list srv_kws = { "SSL", { }, {
+       { "ca-file",               srv_parse_ca_file,        1, 0 }, /* set CAfile to process verify server cert */
        { "check-ssl",             srv_parse_check_ssl,      0, 0 }, /* enable SSL for health checks */
        { "ciphers",               srv_parse_ciphers,        1, 0 }, /* select the cipher suite */
+       { "crl-file",              srv_parse_crl_file,       1, 0 }, /* set certificate revocation list file use on server cert verify */
        { "force-sslv3",           srv_parse_force_sslv3,    0, 0 }, /* force SSLv3 */
        { "force-tlsv10",          srv_parse_force_tlsv10,   0, 0 }, /* force TLSv10 */
        { "force-tlsv11",          srv_parse_force_tlsv11,   0, 0 }, /* force TLSv11 */
@@ -1635,6 +1722,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
        { "no-tlsv12",             srv_parse_no_tlsv12,      0, 0 }, /* disable TLSv12 */
        { "no-tls-tickets",        srv_parse_no_tls_tickets, 0, 0 }, /* disable session resumption tickets */
        { "ssl",                   srv_parse_ssl,            0, 0 }, /* enable SSL processing */
+       { "verify",                srv_parse_verify,         1, 0 }, /* set SSL verify method */
        { NULL, NULL, 0, 0 },
 }};