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.
This commit is contained in:
Emmanuel Hocdet 2019-12-16 16:39:17 +01:00 committed by William Lallemand
parent 0214b45a61
commit 842e94ee06
3 changed files with 54 additions and 18 deletions

View File

@ -718,8 +718,9 @@ The following keywords are supported in the "global" section :
ca-base <dir>
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 <jail dir>
Changes current directory to <jail dir> and performs a chroot() there before
@ -11302,6 +11303,13 @@ ca-sign-pass <passphrase>
the dynamic generation of certificates is enabled. See
'generate-certificates' for details.
ca-verify-file <cafile>
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 <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 <file>
<crtfile> [\[<sslbindconf> ...\]] [[!]<snifilter> ...]
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 <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

View File

@ -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)

View File

@ -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 */