diff --git a/doc/configuration.txt b/doc/configuration.txt index d9a756fdb..598d5d2eb 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -7048,6 +7048,13 @@ backup Supported in default-server: No +ca-file + 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 Supported in default-server: No +crl-file + 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 [/] 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 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 diff --git a/include/types/server.h b/include/types/server.h index 2d2bb87e0..1a69f83d1 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -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 { diff --git a/src/ssl_sock.c b/src/ssl_sock.c index fb59515af..6c9eae4fe 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -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 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 }, }};