From: Emmanuel Hocdet Date: Mon, 16 Dec 2019 15:39:17 +0000 (+0100) Subject: MINOR: ssl: add "ca-verify-file" directive X-Git-Tag: v2.2-dev4~87 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=842e94ee06c2c1e57078d91c28371248cf471386;p=thirdparty%2Fhaproxy.git MINOR: ssl: add "ca-verify-file" directive It's only available for bind line. "ca-verify-file" allows to separate CA certificates from "ca-file". CA names sent in server hello message is only compute from "ca-file". Typically, "ca-file" must be defined with intermediate certificates and "ca-verify-file" with certificates to ending the chain, like root CA. Fix issue #404. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index b60a8d45ca..c09bf00881 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -718,8 +718,9 @@ The following keywords are supported in the "global" section : ca-base Assigns a default directory to fetch SSL CA certificates and CRLs from when a - relative path is used with "ca-file" or "crl-file" directives. Absolute - locations specified in "ca-file" and "crl-file" prevail and ignore "ca-base". + relative path is used with "ca-file", "ca-verify-file" or "crl-file" + directives. Absolute locations specified in "ca-file", "ca-verify-file" and + "crl-file" prevail and ignore "ca-base". chroot Changes current directory to and performs a chroot() there before @@ -11302,6 +11303,13 @@ ca-sign-pass the dynamic generation of certificates is enabled. See 'generate-certificates' for details. +ca-verify-file + This setting designates a PEM file from which to load CA certificates used to + verify client's certificate. It designates CA certificates which must not be + included in CA names sent in server hello message. Typically, "ca-file" must + be defined with intermediate certificates, and "ca-verify-file" with + certificates to ending the chain, like root CA. + ciphers This setting is only available when support for OpenSSL was built in. It sets the string describing the list of cipher algorithms ("cipher suite") that are @@ -11450,10 +11458,10 @@ crt-list [\[ ...\]] [[!] ...] - sslbindconf support "npn", "alpn", "verify", "ca-file", "no-ca-names", - crl-file", "ecdhe", "curves", "ciphers" configuration. With BoringSSL - and Openssl >= 1.1.1 "ssl-min-ver" and "ssl-max-ver" are also supported. - It override the configuration set in bind line for the certificate. + sslbindconf support "npn", "alpn", "verify", "ca-file", "ca-verify-file", + "no-ca-names", "crl-file", "ecdhe", "curves", "ciphers" configuration. With + BoringSSL and Openssl >= 1.1.1 "ssl-min-ver" and "ssl-max-ver" are also + supported. It override the configuration set in bind line for the certificate. Wildcards are supported in the SNI filter. Negative filter are also supported, only useful in combination with a wildcard filter to exclude a particular SNI. @@ -11653,6 +11661,7 @@ nice no-ca-names This setting is only available when support for OpenSSL was built in. It prevents from send CA names in server hello message when ca-file is used. + Use "ca-verify-file" instead of "ca-file" with "no-ca-names". no-sslv3 This setting is only available when support for OpenSSL was built in. It diff --git a/include/types/listener.h b/include/types/listener.h index bcc57ae70a..eca03a4947 100644 --- a/include/types/listener.h +++ b/include/types/listener.h @@ -127,7 +127,8 @@ struct ssl_bind_conf { unsigned int verify:3; /* verify method (set of SSL_VERIFY_* flags) */ unsigned int no_ca_names:1;/* do not send ca names to clients (ca_file related) */ unsigned int early_data:1; /* early data allowed */ - char *ca_file; /* CAfile to use on verify */ + char *ca_file; /* CAfile to use on verify and ca-names */ + char *ca_verify_file; /* CAverify file to use on verify only */ char *crl_file; /* CRLfile to use on verify */ char *ciphers; /* cipher suite to use if non-null */ #if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER) diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 577f785539..efb6b0e0e1 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -4513,6 +4513,8 @@ void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf) #endif free(conf->ca_file); conf->ca_file = NULL; + free(conf->ca_verify_file); + conf->ca_verify_file = NULL; free(conf->crl_file); conf->crl_file = NULL; free(conf->ciphers); @@ -5132,15 +5134,21 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_ SSL_CTX_set_verify(ctx, verify, ssl_sock_bind_verifycbk); if (verify & SSL_VERIFY_PEER) { char *ca_file = (ssl_conf && ssl_conf->ca_file) ? ssl_conf->ca_file : bind_conf->ssl_conf.ca_file; + char *ca_verify_file = (ssl_conf && ssl_conf->ca_verify_file) ? ssl_conf->ca_verify_file : bind_conf->ssl_conf.ca_verify_file; char *crl_file = (ssl_conf && ssl_conf->crl_file) ? ssl_conf->crl_file : bind_conf->ssl_conf.crl_file; - if (ca_file) { + if (ca_file || ca_verify_file) { /* set CAfile to verify */ - if (!ssl_set_verify_locations_file(ctx, ca_file)) { + if (ca_file && !ssl_set_verify_locations_file(ctx, ca_file)) { memprintf(err, "%sProxy '%s': unable to set CA file '%s' for bind '%s' at [%s:%d].\n", err && *err ? *err : "", curproxy->id, ca_file, bind_conf->arg, bind_conf->file, bind_conf->line); cfgerr |= ERR_ALERT | ERR_FATAL; } - if (!((ssl_conf && ssl_conf->no_ca_names) || bind_conf->ssl_conf.no_ca_names)) { + if (ca_verify_file && !ssl_set_verify_locations_file(ctx, ca_verify_file)) { + memprintf(err, "%sProxy '%s': unable to set CA-no-names file '%s' for bind '%s' at [%s:%d].\n", + err && *err ? *err : "", curproxy->id, ca_verify_file, bind_conf->arg, bind_conf->file, bind_conf->line); + cfgerr |= ERR_ALERT | ERR_FATAL; + } + if (ca_file && !((ssl_conf && ssl_conf->no_ca_names) || bind_conf->ssl_conf.no_ca_names)) { /* set CA names for client cert request, function returns void */ SSL_CTX_set_client_CA_list(ctx, SSL_dup_CA_list(ssl_get_client_ca_file(ca_file))); } @@ -8630,8 +8638,8 @@ smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *k return 1; } -/* parse the "ca-file" bind keyword */ -static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +/* for ca-file and ca-verify-file */ +static int ssl_bind_parse_ca_file_common(char **args, int cur_arg, char **ca_file_p, char **err) { if (!*args[cur_arg + 1]) { memprintf(err, "'%s' : missing CAfile path", args[cur_arg]); @@ -8639,21 +8647,37 @@ static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, st } if ((*args[cur_arg + 1] != '/') && global_ssl.ca_base) - memprintf(&conf->ca_file, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]); + memprintf(ca_file_p, "%s/%s", global_ssl.ca_base, args[cur_arg + 1]); else - memprintf(&conf->ca_file, "%s", args[cur_arg + 1]); + memprintf(ca_file_p, "%s", args[cur_arg + 1]); - if (!ssl_store_load_locations_file(conf->ca_file)) { - memprintf(err, "'%s' : unable to load %s", args[cur_arg], conf->ca_file); + if (!ssl_store_load_locations_file(*ca_file_p)) { + memprintf(err, "'%s' : unable to load %s", args[cur_arg], *ca_file_p); return ERR_ALERT | ERR_FATAL; } return 0; } + +/* parse the "ca-file" bind keyword */ +static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +{ + return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_file, err); +} static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { return ssl_bind_parse_ca_file(args, cur_arg, px, &conf->ssl_conf, err); } +/* parse the "ca-verify-file" bind keyword */ +static int ssl_bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err) +{ + return ssl_bind_parse_ca_file_common(args, cur_arg, &conf->ca_verify_file, err); +} +static int bind_parse_ca_verify_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) +{ + return ssl_bind_parse_ca_verify_file(args, cur_arg, px, &conf->ssl_conf, err); +} + /* parse the "ca-sign-file" bind keyword */ static int bind_parse_ca_sign_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) { @@ -11674,7 +11698,8 @@ INITCALL1(STG_REGISTER, acl_register_keywords, &acl_kws); static struct ssl_bind_kw ssl_bind_kws[] = { { "allow-0rtt", ssl_bind_parse_allow_0rtt, 0 }, /* allow 0-RTT */ { "alpn", ssl_bind_parse_alpn, 1 }, /* set ALPN supported protocols */ - { "ca-file", ssl_bind_parse_ca_file, 1 }, /* set CAfile to process verify on client cert */ + { "ca-file", ssl_bind_parse_ca_file, 1 }, /* set CAfile to process ca-names and verify on client cert */ + { "ca-verify-file", ssl_bind_parse_ca_verify_file, 1 }, /* set CAverify file to process verify on client cert */ { "ciphers", ssl_bind_parse_ciphers, 1 }, /* set SSL cipher suite */ #if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L) { "ciphersuites", ssl_bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */ @@ -11695,7 +11720,8 @@ static struct ssl_bind_kw ssl_bind_kws[] = { static struct bind_kw_list bind_kws = { "SSL", { }, { { "allow-0rtt", bind_parse_allow_0rtt, 0 }, /* Allow 0RTT */ { "alpn", bind_parse_alpn, 1 }, /* set ALPN supported protocols */ - { "ca-file", bind_parse_ca_file, 1 }, /* set CAfile to process verify on client cert */ + { "ca-file", bind_parse_ca_file, 1 }, /* set CAfile to process ca-names and verify on client cert */ + { "ca-verify-file", bind_parse_ca_verify_file, 1 }, /* set CAverify file to process verify on client cert */ { "ca-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth > 0 */ { "ca-sign-file", bind_parse_ca_sign_file, 1 }, /* set CAFile used to generate and sign server certs */ { "ca-sign-pass", bind_parse_ca_sign_pass, 1 }, /* set CAKey passphrase */