mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-28 22:31:06 +01:00
MEDIUM: ssl: Set verify 'required' as global default for servers side.
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.
This commit is contained in:
parent
59ad1a2e75
commit
850efd5149
@ -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.
|
||||
|
||||
@ -64,6 +64,12 @@
|
||||
#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;
|
||||
|
||||
@ -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]);
|
||||
|
||||
@ -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')
|
||||
|
||||
@ -86,6 +86,14 @@
|
||||
#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",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user