MAJOR: ssl: bind configuration per certificat

crt-list is extend to support ssl configuration. You can now have
such line in crt-list <file>:
mycert.pem [npn h2,http/1.1]

Support include "npn", "alpn", "verify", "ca_file", "crl_file",
"ecdhe", "ciphers" configuration and ssl options.

"crt-base" is also supported to fetch certificates.
This commit is contained in:
Emmanuel Hocdet 2016-12-29 18:26:15 +01:00 committed by Willy Tarreau
parent 70e2f27212
commit 98263291cc
6 changed files with 356 additions and 115 deletions

View File

@ -10248,10 +10248,14 @@ crt-ignore-err <errors>
crt-list <file> crt-list <file>
This setting is only available when support for OpenSSL was built in. It This setting is only available when support for OpenSSL was built in. It
designates a list of PEM file with an optional list of SNI filter per designates a list of PEM file with an optional ssl configuration and a SNI
certificate, with the following format for each line : filter per certificate, with the following format for each line :
<crtfile> [[!]<snifilter> ...] <crtfile> [\[<sslbindconf> ...\]] [[!]<snifilter> ...]
sslbindconf support "npn", "alpn", "verify", "ca_file", "crl_file", "ecdhe",
"ciphers" configuration and ssl options (see "ssl-default-bind-options").
It override the configuration set in bind line for the certificate.
Wildcards are supported in the SNI filter. Negative filter are also supported, 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. only useful in combination with a wildcard filter to exclude a particular SNI.
@ -10266,6 +10270,12 @@ crt-list <file>
the base name is given in the crt-list. SNI filter will do the same work on the base name is given in the crt-list. SNI filter will do the same work on
all bundled certificates. all bundled certificates.
crt-list file example:
cert1.pem
cert2.pem [npn h2,http/1.1]
certW.pem *.domain.tld !secure.domain.tld
certS.pem [ecdhe secp521r1 ciphers ECDHE-ECDSA-AES256-GCM-SHA384] secure.domain.tld
defer-accept defer-accept
Is an optional keyword which is supported only on certain Linux kernels. It Is an optional keyword which is supported only on certain Linux kernels. It
states that a connection will only be accepted once some data arrive on it, states that a connection will only be accepted once some data arrive on it,

View File

@ -74,8 +74,11 @@
// max # args on a configuration line // max # args on a configuration line
#define MAX_LINE_ARGS 64 #define MAX_LINE_ARGS 64
// crt-list parsing factor for LINESIZE and MAX_LINE_ARGS // maximum line size when parsing crt-bind-list config
#define CRTLIST_FACTOR 32 #define CRT_LINESIZE 65536
// max # args on crt-bind-list configuration line
#define MAX_CRT_ARGS 2048
// max # args on a stats socket // max # args on a stats socket
// This should cover at least 5 + twice the # of data_types // This should cover at least 5 + twice the # of data_types

View File

@ -42,7 +42,7 @@ int ssl_sock_is_ssl(struct connection *conn)
} }
int ssl_sock_handshake(struct connection *conn, unsigned int flag); int ssl_sock_handshake(struct connection *conn, unsigned int flag);
int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx); int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *, SSL_CTX *ctx);
int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf); int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf);
int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf); int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf);
int ssl_sock_prepare_srv_ctx(struct server *srv); int ssl_sock_prepare_srv_ctx(struct server *srv);

View File

@ -115,22 +115,34 @@ enum li_state {
#define BC_SSL_O_NO_TLS_TICKETS 0x0100 /* disable session resumption tickets */ #define BC_SSL_O_NO_TLS_TICKETS 0x0100 /* disable session resumption tickets */
#endif #endif
/* ssl "bind" settings */
struct ssl_bind_conf {
#ifdef USE_OPENSSL
#ifdef OPENSSL_NPN_NEGOTIATED
char *npn_str; /* NPN protocol string */
int npn_len; /* NPN protocol string length */
#endif
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
char *alpn_str; /* ALPN protocol string */
int alpn_len; /* ALPN protocol string length */
#endif
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 */
char *ciphers; /* cipher suite to use if non-null */
char *ecdhe; /* named curve to use for ECDHE */
int ssl_options; /* ssl options */
#endif
};
/* "bind" line settings */ /* "bind" line settings */
struct bind_conf { struct bind_conf {
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
char *ca_file; /* CAfile to use on verify */ struct ssl_bind_conf ssl_conf; /* ssl conf for ctx setting */
unsigned long long ca_ignerr; /* ignored verify errors in handshake if depth > 0 */ unsigned long long ca_ignerr; /* ignored verify errors in handshake if depth > 0 */
unsigned long long crt_ignerr; /* ignored verify errors in handshake if depth == 0 */ unsigned long long crt_ignerr; /* ignored verify errors in handshake if depth == 0 */
char *ciphers; /* cipher suite to use if non-null */
char *crl_file; /* CRLfile to use on verify */
char *ecdhe; /* named curve to use for ECDHE */
int ssl_options; /* ssl options */
int verify; /* verify method (set of SSL_VERIFY_* flags) */
SSL_CTX *default_ctx; /* SSL context of first/default certificate */ SSL_CTX *default_ctx; /* SSL context of first/default certificate */
char *npn_str; /* NPN protocol string */ struct ssl_bind_conf *default_ssl_conf; /* custom SSL conf of default_ctx */
int npn_len; /* NPN protocol string length */
char *alpn_str; /* ALPN protocol string */
int alpn_len; /* ALPN protocol string length */
int strict_sni; /* refuse negotiation if sni doesn't match a certificate */ int strict_sni; /* refuse negotiation if sni doesn't match a certificate */
struct eb_root sni_ctx; /* sni_ctx tree of all known certs full-names sorted by name */ struct eb_root sni_ctx; /* sni_ctx tree of all known certs full-names sorted by name */
struct eb_root sni_w_ctx; /* sni_ctx tree of all known certs wildcards sorted by name */ struct eb_root sni_w_ctx; /* sni_ctx tree of all known certs wildcards sorted by name */
@ -213,6 +225,11 @@ struct bind_kw {
int (*parse)(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err); int (*parse)(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err);
int skip; /* nb of args to skip */ int skip; /* nb of args to skip */
}; };
struct ssl_bind_kw {
const char *kw;
int (*parse)(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err);
int skip; /* nb of args to skip */
};
/* /*
* A keyword list. It is a NULL-terminated array of keywords. It embeds a * A keyword list. It is a NULL-terminated array of keywords. It embeds a

View File

@ -22,6 +22,7 @@
#ifndef _TYPES_SSL_SOCK_H #ifndef _TYPES_SSL_SOCK_H
#define _TYPES_SSL_SOCK_H #define _TYPES_SSL_SOCK_H
#include <types/listener.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <ebmbtree.h> #include <ebmbtree.h>
@ -29,6 +30,7 @@ struct sni_ctx {
SSL_CTX *ctx; /* context associated to the certificate */ SSL_CTX *ctx; /* context associated to the certificate */
int order; /* load order for the certificate */ int order; /* load order for the certificate */
int neg; /* reject if match */ int neg; /* reject if match */
struct ssl_bind_conf *conf; /* ssl "bind" conf for the certificate */
struct ebmb_node name; /* node holding the servername value */ struct ebmb_node name; /* node holding the servername value */
}; };

View File

@ -194,6 +194,8 @@ static char *x509v3_ext_values[X509V3_EXT_SIZE] = {
"nonRepudiation,digitalSignature,keyEncipherment" "nonRepudiation,digitalSignature,keyEncipherment"
}; };
static struct ssl_bind_kw ssl_bind_kws[];
/* LRU cache to store generated certificate */ /* LRU cache to store generated certificate */
static struct lru64_head *ssl_ctx_lru_tree = NULL; static struct lru64_head *ssl_ctx_lru_tree = NULL;
static unsigned int ssl_ctx_lru_seed = 0; static unsigned int ssl_ctx_lru_seed = 0;
@ -1182,7 +1184,7 @@ void ssl_sock_msgcbk(int write_p, int version, int content_type, const void *buf
static int ssl_sock_advertise_npn_protos(SSL *s, const unsigned char **data, static int ssl_sock_advertise_npn_protos(SSL *s, const unsigned char **data,
unsigned int *len, void *arg) unsigned int *len, void *arg)
{ {
struct bind_conf *conf = arg; struct ssl_bind_conf *conf = arg;
*data = (const unsigned char *)conf->npn_str; *data = (const unsigned char *)conf->npn_str;
*len = conf->npn_len; *len = conf->npn_len;
@ -1199,7 +1201,7 @@ static int ssl_sock_advertise_alpn_protos(SSL *s, const unsigned char **out,
const unsigned char *server, const unsigned char *server,
unsigned int server_len, void *arg) unsigned int server_len, void *arg)
{ {
struct bind_conf *conf = arg; struct ssl_bind_conf *conf = arg;
if (SSL_select_next_proto((unsigned char**) out, outlen, (const unsigned char *)conf->alpn_str, if (SSL_select_next_proto((unsigned char**) out, outlen, (const unsigned char *)conf->alpn_str,
conf->alpn_len, server, server_len) != OPENSSL_NPN_NEGOTIATED) { conf->alpn_len, server, server_len) != OPENSSL_NPN_NEGOTIATED) {
@ -1330,7 +1332,7 @@ ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL
SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_get_tmp_dh); SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_get_tmp_dh);
#if defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH) #if defined(SSL_CTX_set_tmp_ecdh) && !defined(OPENSSL_NO_ECDH)
{ {
const char *ecdhe = (bind_conf->ecdhe ? bind_conf->ecdhe : ECDHE_DEFAULT_CURVE); const char *ecdhe = (bind_conf->ssl_conf.ecdhe ? bind_conf->ssl_conf.ecdhe : ECDHE_DEFAULT_CURVE);
EC_KEY *ecc; EC_KEY *ecc;
int nid; int nid;
@ -1776,7 +1778,8 @@ int ssl_sock_load_dh_params(SSL_CTX *ctx, const char *file)
} }
#endif #endif
static int ssl_sock_add_cert_sni(SSL_CTX *ctx, struct bind_conf *s, char *name, int order) static int ssl_sock_add_cert_sni(SSL_CTX *ctx, struct bind_conf *s,
struct ssl_bind_conf *conf, char *name, int order)
{ {
struct sni_ctx *sc; struct sni_ctx *sc;
int wild = 0, neg = 0; int wild = 0, neg = 0;
@ -1809,7 +1812,7 @@ static int ssl_sock_add_cert_sni(SSL_CTX *ctx, struct bind_conf *s, char *name,
node = ebst_lookup(&s->sni_ctx, trash.str); node = ebst_lookup(&s->sni_ctx, trash.str);
for (; node; node = ebmb_next_dup(node)) { for (; node; node = ebmb_next_dup(node)) {
sc = ebmb_entry(node, struct sni_ctx, name); sc = ebmb_entry(node, struct sni_ctx, name);
if (sc->ctx == ctx && sc->neg == neg) if (sc->ctx == ctx && sc->conf == conf && sc->neg == neg)
return order; return order;
} }
@ -1818,6 +1821,7 @@ static int ssl_sock_add_cert_sni(SSL_CTX *ctx, struct bind_conf *s, char *name,
return order; return order;
memcpy(sc->name.key, trash.str, len + 1); memcpy(sc->name.key, trash.str, len + 1);
sc->ctx = ctx; sc->ctx = ctx;
sc->conf = conf;
sc->order = order++; sc->order = order++;
sc->neg = neg; sc->neg = neg;
if (wild) if (wild)
@ -2072,7 +2076,8 @@ static void ssl_sock_populate_sni_keytypes_hplr(const char *str, struct eb_root
* 0 on success * 0 on success
* 1 on failure * 1 on failure
*/ */
static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, char **sni_filter, int fcount, char **err) static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf,
char **sni_filter, int fcount, char **err)
{ {
char fp[MAXPATHLEN+1] = {0}; char fp[MAXPATHLEN+1] = {0};
int n = 0; int n = 0;
@ -2246,7 +2251,7 @@ static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_con
} }
/* Update SNI Tree */ /* Update SNI Tree */
key_combos[i-1].order = ssl_sock_add_cert_sni(cur_ctx, bind_conf, str, key_combos[i-1].order); key_combos[i-1].order = ssl_sock_add_cert_sni(cur_ctx, bind_conf, ssl_conf, str, key_combos[i-1].order);
node = ebmb_next(node); node = ebmb_next(node);
} }
@ -2256,6 +2261,7 @@ static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_con
for (i = SSL_SOCK_POSSIBLE_KT_COMBOS - 1; i >= 0; i--) { for (i = SSL_SOCK_POSSIBLE_KT_COMBOS - 1; i >= 0; i--) {
if (key_combos[i].ctx) { if (key_combos[i].ctx) {
bind_conf->default_ctx = key_combos[i].ctx; bind_conf->default_ctx = key_combos[i].ctx;
bind_conf->default_ssl_conf = ssl_conf;
break; break;
} }
} }
@ -2280,7 +2286,8 @@ static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_con
} }
#else #else
/* This is a dummy, that just logs an error and returns error */ /* This is a dummy, that just logs an error and returns error */
static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, char **sni_filter, int fcount, char **err) static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf,
char **sni_filter, int fcount, char **err)
{ {
memprintf(err, "%sunable to stat SSL certificate from file '%s' : %s.\n", memprintf(err, "%sunable to stat SSL certificate from file '%s' : %s.\n",
err && *err ? *err : "", path, strerror(errno)); err && *err ? *err : "", path, strerror(errno));
@ -2292,7 +2299,8 @@ static int ssl_sock_load_multi_cert(const char *path, struct bind_conf *bind_con
/* Loads a certificate key and CA chain from a file. Returns 0 on error, -1 if /* Loads a certificate key and CA chain from a file. Returns 0 on error, -1 if
* an early error happens and the caller must call SSL_CTX_free() by itelf. * an early error happens and the caller must call SSL_CTX_free() by itelf.
*/ */
static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct bind_conf *s, char **sni_filter, int fcount) static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct bind_conf *s,
struct ssl_bind_conf *ssl_conf, char **sni_filter, int fcount)
{ {
BIO *in; BIO *in;
X509 *x = NULL, *ca; X509 *x = NULL, *ca;
@ -2325,7 +2333,7 @@ static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct
if (fcount) { if (fcount) {
while (fcount--) while (fcount--)
order = ssl_sock_add_cert_sni(ctx, s, sni_filter[fcount], order); order = ssl_sock_add_cert_sni(ctx, s, ssl_conf, sni_filter[fcount], order);
} }
else { else {
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@ -2335,7 +2343,7 @@ static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct
GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i); GENERAL_NAME *name = sk_GENERAL_NAME_value(names, i);
if (name->type == GEN_DNS) { if (name->type == GEN_DNS) {
if (ASN1_STRING_to_UTF8((unsigned char **)&str, name->d.dNSName) >= 0) { if (ASN1_STRING_to_UTF8((unsigned char **)&str, name->d.dNSName) >= 0) {
order = ssl_sock_add_cert_sni(ctx, s, str, order); order = ssl_sock_add_cert_sni(ctx, s, ssl_conf, str, order);
OPENSSL_free(str); OPENSSL_free(str);
} }
} }
@ -2351,7 +2359,7 @@ static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct
value = X509_NAME_ENTRY_get_data(entry); value = X509_NAME_ENTRY_get_data(entry);
if (ASN1_STRING_to_UTF8((unsigned char **)&str, value) >= 0) { if (ASN1_STRING_to_UTF8((unsigned char **)&str, value) >= 0) {
order = ssl_sock_add_cert_sni(ctx, s, str, order); order = ssl_sock_add_cert_sni(ctx, s, ssl_conf, str, order);
OPENSSL_free(str); OPENSSL_free(str);
} }
} }
@ -2394,7 +2402,8 @@ static int ssl_sock_load_cert_chain_file(SSL_CTX *ctx, const char *file, struct
return ret; return ret;
} }
static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf, char **sni_filter, int fcount, char **err) static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf,
char **sni_filter, int fcount, char **err)
{ {
int ret; int ret;
SSL_CTX *ctx; SSL_CTX *ctx;
@ -2413,7 +2422,7 @@ static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf
return 1; return 1;
} }
ret = ssl_sock_load_cert_chain_file(ctx, path, bind_conf, sni_filter, fcount); ret = ssl_sock_load_cert_chain_file(ctx, path, bind_conf, ssl_conf, sni_filter, fcount);
if (ret <= 0) { if (ret <= 0) {
memprintf(err, "%sunable to load SSL certificate from PEM file '%s'.\n", memprintf(err, "%sunable to load SSL certificate from PEM file '%s'.\n",
err && *err ? *err : "", path); err && *err ? *err : "", path);
@ -2476,8 +2485,10 @@ static int ssl_sock_load_cert_file(const char *path, struct bind_conf *bind_conf
return 1; return 1;
} }
#endif #endif
if (!bind_conf->default_ctx) if (!bind_conf->default_ctx) {
bind_conf->default_ctx = ctx; bind_conf->default_ctx = ctx;
bind_conf->default_ssl_conf = ssl_conf;
}
return 0; return 0;
} }
@ -2499,7 +2510,7 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err)
if (stat(path, &buf) == 0) { if (stat(path, &buf) == 0) {
dir = opendir(path); dir = opendir(path);
if (!dir) if (!dir)
return ssl_sock_load_cert_file(path, bind_conf, NULL, 0, err); return ssl_sock_load_cert_file(path, bind_conf, NULL, NULL, 0, err);
/* strip trailing slashes, including first one */ /* strip trailing slashes, including first one */
for (end = path + strlen(path) - 1; end >= path && *end == '/'; end--) for (end = path + strlen(path) - 1; end >= path && *end == '/'; end--)
@ -2559,7 +2570,7 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err)
} }
snprintf(fp, sizeof(fp), "%s/%s", path, dp); snprintf(fp, sizeof(fp), "%s/%s", path, dp);
ssl_sock_load_multi_cert(fp, bind_conf, NULL, 0, err); ssl_sock_load_multi_cert(fp, bind_conf, NULL, NULL, 0, err);
/* Successfully processed the bundle */ /* Successfully processed the bundle */
goto ignore_entry; goto ignore_entry;
@ -2567,7 +2578,7 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err)
} }
#endif #endif
cfgerr += ssl_sock_load_cert_file(fp, bind_conf, NULL, 0, err); cfgerr += ssl_sock_load_cert_file(fp, bind_conf, NULL, NULL, 0, err);
ignore_entry: ignore_entry:
free(de); free(de);
} }
@ -2577,7 +2588,7 @@ int ssl_sock_load_cert(char *path, struct bind_conf *bind_conf, char **err)
return cfgerr; return cfgerr;
} }
cfgerr = ssl_sock_load_multi_cert(path, bind_conf, NULL, 0, err); cfgerr = ssl_sock_load_multi_cert(path, bind_conf, NULL, NULL, 0, err);
return cfgerr; return cfgerr;
} }
@ -2598,9 +2609,33 @@ static int ssl_initialize_random()
return random_initialized; return random_initialized;
} }
int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, char **err) /* release ssl bind conf */
void ssl_sock_free_ssl_conf(struct ssl_bind_conf *conf)
{ {
char thisline[LINESIZE*CRTLIST_FACTOR]; if (conf) {
#ifdef OPENSSL_NPN_NEGOTIATED
free(conf->npn_str);
conf->npn_str = NULL;
#endif
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
free(conf->alpn_str);
conf->alpn_str = NULL;
#endif
free(conf->ca_file);
conf->ca_file = NULL;
free(conf->crl_file);
conf->crl_file = NULL;
free(conf->ciphers);
conf->ciphers = NULL;
free(conf->ecdhe);
conf->ecdhe = NULL;
}
}
int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, struct proxy *curproxy, char **err)
{
char thisline[CRT_LINESIZE];
char path[MAXPATHLEN+1];
FILE *f; FILE *f;
struct stat buf; struct stat buf;
int linenum = 0; int linenum = 0;
@ -2612,11 +2647,12 @@ int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, char *
} }
while (fgets(thisline, sizeof(thisline), f) != NULL) { while (fgets(thisline, sizeof(thisline), f) != NULL) {
int arg; int arg, newarg, cur_arg, i, ssl_b = 0, ssl_e = 0;
int newarg;
char *end; char *end;
char *args[MAX_LINE_ARGS*CRTLIST_FACTOR + 1]; char *args[MAX_CRT_ARGS + 1];
char *line = thisline; char *line = thisline;
char *crt_path;
struct ssl_bind_conf *ssl_conf = NULL;
linenum++; linenum++;
end = line + strlen(line); end = line + strlen(line);
@ -2637,15 +2673,40 @@ int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, char *
/* end of string, end of loop */ /* end of string, end of loop */
*line = 0; *line = 0;
break; break;
} } else if (isspace(*line)) {
else if (isspace(*line)) {
newarg = 1; newarg = 1;
*line = 0; *line = 0;
} else if (*line == '[') {
if (ssl_b) {
memprintf(err, "too many '[' on line %d in file '%s'.", linenum, file);
cfgerr = 1;
break;
} }
else if (newarg) { if (!arg) {
if (arg == MAX_LINE_ARGS*CRTLIST_FACTOR) { memprintf(err, "file must start with a cert on line %d in file '%s'", linenum, file);
memprintf(err, "too many args on line %d in file '%s'.", cfgerr = 1;
linenum, file); break;
}
ssl_b = arg;
newarg = 1;
*line = 0;
} else if (*line == ']') {
if (ssl_e) {
memprintf(err, "too many ']' on line %d in file '%s'.", linenum, file);
cfgerr = 1;
break;
}
if (!ssl_b) {
memprintf(err, "missing '[' in line %d in file '%s'.", linenum, file);
cfgerr = 1;
break;
}
ssl_e = arg;
newarg = 1;
*line = 0;
} else if (newarg) {
if (arg == MAX_CRT_ARGS) {
memprintf(err, "too many args on line %d in file '%s'.", linenum, file);
cfgerr = 1; cfgerr = 1;
break; break;
} }
@ -2656,15 +2717,61 @@ int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, char *
} }
if (cfgerr) if (cfgerr)
break; break;
args[arg++] = line;
/* empty line */ /* empty line */
if (!arg) if (!*args[0])
continue; continue;
if (stat(args[0], &buf) == 0) { crt_path = args[0];
cfgerr = ssl_sock_load_cert_file(args[0], bind_conf, &args[1], arg-1, err); if (*crt_path != '/' && global_ssl.crt_base) {
if ((strlen(global_ssl.crt_base) + 1 + strlen(crt_path)) > MAXPATHLEN) {
memprintf(err, "'%s' : path too long on line %d in file '%s'",
crt_path, linenum, file);
cfgerr = 1;
break;
}
snprintf(path, sizeof(path), "%s/%s", global_ssl.crt_base, crt_path);
crt_path = path;
}
ssl_conf = calloc(1, sizeof *ssl_conf);
cur_arg = ssl_b ? ssl_b : 1;
while (cur_arg < ssl_e) {
newarg = 0;
for (i = 0; ssl_bind_kws[i].kw != NULL; i++) {
if (strcmp(ssl_bind_kws[i].kw, args[cur_arg]) == 0) {
newarg = 1;
cfgerr = ssl_bind_kws[i].parse(args, cur_arg, curproxy, ssl_conf, err);
if (cur_arg + 1 + ssl_bind_kws[i].skip > ssl_e) {
memprintf(err, "ssl args out of '[]' for %s on line %d in file '%s'",
args[cur_arg], linenum, file);
cfgerr = 1;
}
cur_arg += 1 + ssl_bind_kws[i].skip;
break;
}
}
if (!cfgerr && !newarg) {
memprintf(err, "unknown ssl keyword %s on line %d in file '%s'.",
args[cur_arg], linenum, file);
cfgerr = 1;
break;
}
}
if (cfgerr) {
ssl_sock_free_ssl_conf(ssl_conf);
free(ssl_conf);
ssl_conf = NULL;
break;
}
if (stat(crt_path, &buf) == 0) {
cfgerr = ssl_sock_load_cert_file(crt_path, bind_conf, ssl_conf,
&args[cur_arg], arg - cur_arg - 1, err);
} else { } else {
cfgerr = ssl_sock_load_multi_cert(args[0], bind_conf, &args[1], arg-1, err); cfgerr = ssl_sock_load_multi_cert(crt_path, bind_conf, ssl_conf,
&args[cur_arg], arg - cur_arg - 1, err);
} }
if (cfgerr) { if (cfgerr) {
@ -2712,7 +2819,7 @@ int ssl_sock_load_cert_list_file(char *file, struct bind_conf *bind_conf, char *
#define SSL_MODE_SMALL_BUFFERS 0 #define SSL_MODE_SMALL_BUFFERS 0
#endif #endif
int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx) int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, struct ssl_bind_conf *ssl_conf, SSL_CTX *ctx)
{ {
struct proxy *curproxy = bind_conf->frontend; struct proxy *curproxy = bind_conf->frontend;
int cfgerr = 0; int cfgerr = 0;
@ -2741,6 +2848,9 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx)
int idx = 0; int idx = 0;
int dhe_found = 0; int dhe_found = 0;
SSL *ssl = NULL; SSL *ssl = NULL;
struct ssl_bind_conf *ssl_conf_cur;
int conf_ssl_options = bind_conf->ssl_conf.ssl_options | (ssl_conf ? ssl_conf->ssl_options : 0);
const char *conf_ciphers;
/* Make sure openssl opens /dev/urandom before the chroot */ /* Make sure openssl opens /dev/urandom before the chroot */
if (!ssl_initialize_random()) { if (!ssl_initialize_random()) {
@ -2748,17 +2858,17 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx)
cfgerr++; cfgerr++;
} }
if (bind_conf->ssl_options & BC_SSL_O_NO_SSLV3) if (conf_ssl_options & BC_SSL_O_NO_SSLV3)
ssloptions |= SSL_OP_NO_SSLv3; ssloptions |= SSL_OP_NO_SSLv3;
if (bind_conf->ssl_options & BC_SSL_O_NO_TLSV10) if (conf_ssl_options & BC_SSL_O_NO_TLSV10)
ssloptions |= SSL_OP_NO_TLSv1; ssloptions |= SSL_OP_NO_TLSv1;
if (bind_conf->ssl_options & BC_SSL_O_NO_TLSV11) if (conf_ssl_options & BC_SSL_O_NO_TLSV11)
ssloptions |= SSL_OP_NO_TLSv1_1; ssloptions |= SSL_OP_NO_TLSv1_1;
if (bind_conf->ssl_options & BC_SSL_O_NO_TLSV12) if (conf_ssl_options & BC_SSL_O_NO_TLSV12)
ssloptions |= SSL_OP_NO_TLSv1_2; ssloptions |= SSL_OP_NO_TLSv1_2;
if (bind_conf->ssl_options & BC_SSL_O_NO_TLS_TICKETS) if (conf_ssl_options & BC_SSL_O_NO_TLS_TICKETS)
ssloptions |= SSL_OP_NO_TICKET; ssloptions |= SSL_OP_NO_TICKET;
if (bind_conf->ssl_options & BC_SSL_O_USE_SSLV3) { if (conf_ssl_options & BC_SSL_O_USE_SSLV3) {
#ifndef OPENSSL_NO_SSL3 #ifndef OPENSSL_NO_SSL3
SSL_CTX_set_ssl_version(ctx, SSLv3_server_method()); SSL_CTX_set_ssl_version(ctx, SSLv3_server_method());
#else #else
@ -2766,20 +2876,20 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx)
cfgerr++; cfgerr++;
#endif #endif
} }
if (bind_conf->ssl_options & BC_SSL_O_USE_TLSV10) if (conf_ssl_options & BC_SSL_O_USE_TLSV10)
SSL_CTX_set_ssl_version(ctx, TLSv1_server_method()); SSL_CTX_set_ssl_version(ctx, TLSv1_server_method());
#if SSL_OP_NO_TLSv1_1 #if SSL_OP_NO_TLSv1_1
if (bind_conf->ssl_options & BC_SSL_O_USE_TLSV11) if (conf_ssl_options & BC_SSL_O_USE_TLSV11)
SSL_CTX_set_ssl_version(ctx, TLSv1_1_server_method()); SSL_CTX_set_ssl_version(ctx, TLSv1_1_server_method());
#endif #endif
#if SSL_OP_NO_TLSv1_2 #if SSL_OP_NO_TLSv1_2
if (bind_conf->ssl_options & BC_SSL_O_USE_TLSV12) if (conf_ssl_options & BC_SSL_O_USE_TLSV12)
SSL_CTX_set_ssl_version(ctx, TLSv1_2_server_method()); SSL_CTX_set_ssl_version(ctx, TLSv1_2_server_method());
#endif #endif
SSL_CTX_set_options(ctx, ssloptions); SSL_CTX_set_options(ctx, ssloptions);
SSL_CTX_set_mode(ctx, sslmode); SSL_CTX_set_mode(ctx, sslmode);
switch (bind_conf->verify) { switch ((ssl_conf && ssl_conf->verify) ? ssl_conf->verify : bind_conf->ssl_conf.verify) {
case SSL_SOCK_VERIFY_NONE: case SSL_SOCK_VERIFY_NONE:
verify = SSL_VERIFY_NONE; verify = SSL_VERIFY_NONE;
break; break;
@ -2792,15 +2902,17 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx)
} }
SSL_CTX_set_verify(ctx, verify, ssl_sock_bind_verifycbk); SSL_CTX_set_verify(ctx, verify, ssl_sock_bind_verifycbk);
if (verify & SSL_VERIFY_PEER) { if (verify & SSL_VERIFY_PEER) {
if (bind_conf->ca_file) { char *ca_file = (ssl_conf && ssl_conf->ca_file) ? ssl_conf->ca_file : bind_conf->ssl_conf.ca_file;
char *crl_file = (ssl_conf && ssl_conf->crl_file) ? ssl_conf->crl_file : bind_conf->ssl_conf.crl_file;
if (ca_file) {
/* load CAfile to verify */ /* load CAfile to verify */
if (!SSL_CTX_load_verify_locations(ctx, bind_conf->ca_file, NULL)) { if (!SSL_CTX_load_verify_locations(ctx, ca_file, NULL)) {
Alert("Proxy '%s': unable to load CA file '%s' for bind '%s' at [%s:%d].\n", Alert("Proxy '%s': unable to load CA file '%s' for bind '%s' at [%s:%d].\n",
curproxy->id, bind_conf->ca_file, bind_conf->arg, bind_conf->file, bind_conf->line); curproxy->id, ca_file, bind_conf->arg, bind_conf->file, bind_conf->line);
cfgerr++; cfgerr++;
} }
/* set CA names fo client cert request, function returns void */ /* 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)); SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(ca_file));
} }
else { else {
Alert("Proxy '%s': verify is enabled but no CA file specified for bind '%s' at [%s:%d].\n", Alert("Proxy '%s': verify is enabled but no CA file specified for bind '%s' at [%s:%d].\n",
@ -2808,12 +2920,12 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx)
cfgerr++; cfgerr++;
} }
#ifdef X509_V_FLAG_CRL_CHECK #ifdef X509_V_FLAG_CRL_CHECK
if (bind_conf->crl_file) { if (crl_file) {
X509_STORE *store = SSL_CTX_get_cert_store(ctx); X509_STORE *store = SSL_CTX_get_cert_store(ctx);
if (!store || !X509_STORE_load_locations(store, bind_conf->crl_file, NULL)) { if (!store || !X509_STORE_load_locations(store, crl_file, NULL)) {
Alert("Proxy '%s': unable to configure CRL file '%s' for bind '%s' at [%s:%d].\n", Alert("Proxy '%s': unable to configure CRL file '%s' for bind '%s' at [%s:%d].\n",
curproxy->id, bind_conf->crl_file, bind_conf->arg, bind_conf->file, bind_conf->line); curproxy->id, crl_file, bind_conf->arg, bind_conf->file, bind_conf->line);
cfgerr++; cfgerr++;
} }
else { else {
@ -2838,10 +2950,11 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx)
SSL_CTX_set_timeout(ctx, global_ssl.life_time); SSL_CTX_set_timeout(ctx, global_ssl.life_time);
shared_context_set_cache(ctx); shared_context_set_cache(ctx);
if (bind_conf->ciphers && conf_ciphers = (ssl_conf && ssl_conf->ciphers) ? ssl_conf->ciphers : bind_conf->ssl_conf.ciphers;
!SSL_CTX_set_cipher_list(ctx, bind_conf->ciphers)) { if (conf_ciphers &&
!SSL_CTX_set_cipher_list(ctx, conf_ciphers)) {
Alert("Proxy '%s': unable to set SSL cipher list to '%s' for bind '%s' at [%s:%d].\n", Alert("Proxy '%s': unable to set SSL cipher list to '%s' for bind '%s' at [%s:%d].\n",
curproxy->id, bind_conf->ciphers, bind_conf->arg, bind_conf->file, bind_conf->line); curproxy->id, conf_ciphers, bind_conf->arg, bind_conf->file, bind_conf->line);
cfgerr++; cfgerr++;
} }
@ -2905,12 +3018,22 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx)
#endif #endif
#ifdef OPENSSL_NPN_NEGOTIATED #ifdef OPENSSL_NPN_NEGOTIATED
if (bind_conf->npn_str) ssl_conf_cur = NULL;
SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_sock_advertise_npn_protos, bind_conf); if (ssl_conf && ssl_conf->npn_str)
ssl_conf_cur = ssl_conf;
else if (bind_conf->ssl_conf.npn_str)
ssl_conf_cur = &bind_conf->ssl_conf;
if (ssl_conf_cur)
SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_sock_advertise_npn_protos, ssl_conf_cur);
#endif #endif
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
if (bind_conf->alpn_str) ssl_conf_cur = NULL;
SSL_CTX_set_alpn_select_cb(ctx, ssl_sock_advertise_alpn_protos, bind_conf); if (ssl_conf && ssl_conf->alpn_str)
ssl_conf_cur = ssl_conf;
else if (bind_conf->ssl_conf.alpn_str)
ssl_conf_cur = &bind_conf->ssl_conf;
if (ssl_conf_cur)
SSL_CTX_set_alpn_select_cb(ctx, ssl_sock_advertise_alpn_protos, ssl_conf_cur);
#endif #endif
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
@ -2921,12 +3044,13 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx)
{ {
int i; int i;
EC_KEY *ecdh; EC_KEY *ecdh;
const char *ecdhe = (ssl_conf && ssl_conf->ecdhe) ? ssl_conf->ecdhe :
(bind_conf->ssl_conf.ecdhe ? bind_conf->ssl_conf.ecdhe : ECDHE_DEFAULT_CURVE);
i = OBJ_sn2nid(bind_conf->ecdhe ? bind_conf->ecdhe : ECDHE_DEFAULT_CURVE); i = OBJ_sn2nid(ecdhe);
if (!i || ((ecdh = EC_KEY_new_by_curve_name(i)) == NULL)) { if (!i || ((ecdh = EC_KEY_new_by_curve_name(i)) == NULL)) {
Alert("Proxy '%s': unable to set elliptic named curve to '%s' for bind '%s' at [%s:%d].\n", Alert("Proxy '%s': unable to set elliptic named curve to '%s' for bind '%s' at [%s:%d].\n",
curproxy->id, bind_conf->ecdhe ? bind_conf->ecdhe : ECDHE_DEFAULT_CURVE, curproxy->id, ecdhe, bind_conf->arg, bind_conf->file, bind_conf->line);
bind_conf->arg, bind_conf->file, bind_conf->line);
cfgerr++; cfgerr++;
} }
else { else {
@ -3241,7 +3365,7 @@ int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf)
global.ssl_used_frontend = 1; global.ssl_used_frontend = 1;
if (bind_conf->default_ctx) if (bind_conf->default_ctx)
err += ssl_sock_prepare_ctx(bind_conf, bind_conf->default_ctx); err += ssl_sock_prepare_ctx(bind_conf, bind_conf->default_ssl_conf, bind_conf->default_ctx);
node = ebmb_first(&bind_conf->sni_ctx); node = ebmb_first(&bind_conf->sni_ctx);
while (node) { while (node) {
@ -3249,7 +3373,7 @@ int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf)
if (!sni->order && sni->ctx != bind_conf->default_ctx) if (!sni->order && sni->ctx != bind_conf->default_ctx)
/* only initialize the CTX on its first occurrence and /* only initialize the CTX on its first occurrence and
if it is not the default_ctx */ if it is not the default_ctx */
err += ssl_sock_prepare_ctx(bind_conf, sni->ctx); err += ssl_sock_prepare_ctx(bind_conf, sni->conf, sni->ctx);
node = ebmb_next(node); node = ebmb_next(node);
} }
@ -3259,7 +3383,7 @@ int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf)
if (!sni->order && sni->ctx != bind_conf->default_ctx) if (!sni->order && sni->ctx != bind_conf->default_ctx)
/* only initialize the CTX on its first occurrence and /* only initialize the CTX on its first occurrence and
if it is not the default_ctx */ if it is not the default_ctx */
err += ssl_sock_prepare_ctx(bind_conf, sni->ctx); err += ssl_sock_prepare_ctx(bind_conf, sni->conf, sni->ctx);
node = ebmb_next(node); node = ebmb_next(node);
} }
return err; return err;
@ -3330,8 +3454,12 @@ void ssl_sock_free_all_ctx(struct bind_conf *bind_conf)
sni = ebmb_entry(node, struct sni_ctx, name); sni = ebmb_entry(node, struct sni_ctx, name);
back = ebmb_next(node); back = ebmb_next(node);
ebmb_delete(node); ebmb_delete(node);
if (!sni->order) /* only free the CTX on its first occurrence */ if (!sni->order) { /* only free the CTX on its first occurrence */
SSL_CTX_free(sni->ctx); SSL_CTX_free(sni->ctx);
ssl_sock_free_ssl_conf(sni->conf);
free(sni->conf);
sni->conf = NULL;
}
free(sni); free(sni);
node = back; node = back;
} }
@ -3341,13 +3469,18 @@ void ssl_sock_free_all_ctx(struct bind_conf *bind_conf)
sni = ebmb_entry(node, struct sni_ctx, name); sni = ebmb_entry(node, struct sni_ctx, name);
back = ebmb_next(node); back = ebmb_next(node);
ebmb_delete(node); ebmb_delete(node);
if (!sni->order) /* only free the CTX on its first occurrence */ if (!sni->order) { /* only free the CTX on its first occurrence */
SSL_CTX_free(sni->ctx); SSL_CTX_free(sni->ctx);
ssl_sock_free_ssl_conf(sni->conf);
free(sni->conf);
sni->conf = NULL;
}
free(sni); free(sni);
node = back; node = back;
} }
bind_conf->default_ctx = NULL; bind_conf->default_ctx = NULL;
bind_conf->default_ssl_conf = NULL;
} }
/* Destroys all the contexts for a bind_conf. This is used during deinit(). */ /* Destroys all the contexts for a bind_conf. This is used during deinit(). */
@ -3355,12 +3488,9 @@ void ssl_sock_destroy_bind_conf(struct bind_conf *bind_conf)
{ {
ssl_sock_free_ca(bind_conf); ssl_sock_free_ca(bind_conf);
ssl_sock_free_all_ctx(bind_conf); ssl_sock_free_all_ctx(bind_conf);
free(bind_conf->ca_file); ssl_sock_free_ssl_conf(&bind_conf->ssl_conf);
free(bind_conf->ca_sign_file); free(bind_conf->ca_sign_file);
free(bind_conf->ca_sign_pass); free(bind_conf->ca_sign_pass);
free(bind_conf->ciphers);
free(bind_conf->ecdhe);
free(bind_conf->crl_file);
if (bind_conf->keys_ref) { if (bind_conf->keys_ref) {
free(bind_conf->keys_ref->filename); free(bind_conf->keys_ref->filename);
free(bind_conf->keys_ref->tlskeys); free(bind_conf->keys_ref->tlskeys);
@ -3368,12 +3498,8 @@ void ssl_sock_destroy_bind_conf(struct bind_conf *bind_conf)
free(bind_conf->keys_ref); free(bind_conf->keys_ref);
} }
bind_conf->keys_ref = NULL; bind_conf->keys_ref = NULL;
bind_conf->crl_file = NULL;
bind_conf->ecdhe = NULL;
bind_conf->ciphers = NULL;
bind_conf->ca_sign_pass = NULL; bind_conf->ca_sign_pass = NULL;
bind_conf->ca_sign_file = NULL; bind_conf->ca_sign_file = NULL;
bind_conf->ca_file = NULL;
} }
/* Load CA cert file and private key used to generate certificates */ /* Load CA cert file and private key used to generate certificates */
@ -5249,7 +5375,7 @@ smp_fetch_ssl_c_verify(const struct arg *args, struct sample *smp, const char *k
} }
/* parse the "ca-file" bind keyword */ /* parse the "ca-file" bind keyword */
static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
if (!*args[cur_arg + 1]) { if (!*args[cur_arg + 1]) {
if (err) if (err)
@ -5264,6 +5390,10 @@ static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct
return 0; return 0;
} }
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-sign-file" bind keyword */ /* 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) static int bind_parse_ca_sign_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
@ -5295,7 +5425,7 @@ static int bind_parse_ca_sign_pass(char **args, int cur_arg, struct proxy *px, s
} }
/* parse the "ciphers" bind keyword */ /* parse the "ciphers" bind keyword */
static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
if (!*args[cur_arg + 1]) { if (!*args[cur_arg + 1]) {
memprintf(err, "'%s' : missing cipher suite", args[cur_arg]); memprintf(err, "'%s' : missing cipher suite", args[cur_arg]);
@ -5306,7 +5436,10 @@ static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct
conf->ciphers = strdup(args[cur_arg + 1]); conf->ciphers = strdup(args[cur_arg + 1]);
return 0; return 0;
} }
static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_ciphers(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "crt" bind keyword */ /* parse the "crt" bind keyword */
static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int bind_parse_crt(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{ {
@ -5343,7 +5476,7 @@ static int bind_parse_crt_list(char **args, int cur_arg, struct proxy *px, struc
return ERR_ALERT | ERR_FATAL; return ERR_ALERT | ERR_FATAL;
} }
if (ssl_sock_load_cert_list_file(args[cur_arg + 1], conf, err) > 0) { if (ssl_sock_load_cert_list_file(args[cur_arg + 1], conf, px, err) > 0) {
memprintf(err, "'%s' : %s", args[cur_arg], *err); memprintf(err, "'%s' : %s", args[cur_arg], *err);
return ERR_ALERT | ERR_FATAL; return ERR_ALERT | ERR_FATAL;
} }
@ -5352,7 +5485,7 @@ static int bind_parse_crt_list(char **args, int cur_arg, struct proxy *px, struc
} }
/* parse the "crl-file" bind keyword */ /* parse the "crl-file" bind keyword */
static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
#ifndef X509_V_FLAG_CRL_CHECK #ifndef X509_V_FLAG_CRL_CHECK
if (err) if (err)
@ -5373,9 +5506,13 @@ static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struc
return 0; return 0;
#endif #endif
} }
static int bind_parse_crl_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_crl_file(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "ecdhe" bind keyword keyword */ /* parse the "ecdhe" bind keyword keyword */
static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
#if OPENSSL_VERSION_NUMBER < 0x0090800fL #if OPENSSL_VERSION_NUMBER < 0x0090800fL
if (err) if (err)
@ -5397,6 +5534,10 @@ static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct b
return 0; return 0;
#endif #endif
} }
static int bind_parse_ecdhe(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_ecdhe(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "crt-ignore-err" and "ca-ignore-err" bind keywords */ /* parse the "crt-ignore-err" and "ca-ignore-err" bind keywords */
static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
@ -5437,21 +5578,29 @@ static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, str
} }
/* parse the "force-sslv3" bind keyword */ /* parse the "force-sslv3" bind keyword */
static int bind_parse_force_sslv3(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_force_sslv3(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
conf->ssl_options |= BC_SSL_O_USE_SSLV3; conf->ssl_options |= BC_SSL_O_USE_SSLV3;
return 0; return 0;
} }
static int bind_parse_force_sslv3(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_force_sslv3(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "force-tlsv10" bind keyword */ /* parse the "force-tlsv10" bind keyword */
static int bind_parse_force_tlsv10(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_force_tlsv10(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
conf->ssl_options |= BC_SSL_O_USE_TLSV10; conf->ssl_options |= BC_SSL_O_USE_TLSV10;
return 0; return 0;
} }
static int bind_parse_force_tlsv10(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_force_tlsv10(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "force-tlsv11" bind keyword */ /* parse the "force-tlsv11" bind keyword */
static int bind_parse_force_tlsv11(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_force_tlsv11(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
#if SSL_OP_NO_TLSv1_1 #if SSL_OP_NO_TLSv1_1
conf->ssl_options |= BC_SSL_O_USE_TLSV11; conf->ssl_options |= BC_SSL_O_USE_TLSV11;
@ -5462,9 +5611,13 @@ static int bind_parse_force_tlsv11(char **args, int cur_arg, struct proxy *px, s
return ERR_ALERT | ERR_FATAL; return ERR_ALERT | ERR_FATAL;
#endif #endif
} }
static int bind_parse_force_tlsv11(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_force_tlsv11(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "force-tlsv12" bind keyword */ /* parse the "force-tlsv12" bind keyword */
static int bind_parse_force_tlsv12(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_force_tlsv12(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
#if SSL_OP_NO_TLSv1_2 #if SSL_OP_NO_TLSv1_2
conf->ssl_options |= BC_SSL_O_USE_TLSV12; conf->ssl_options |= BC_SSL_O_USE_TLSV12;
@ -5475,46 +5628,68 @@ static int bind_parse_force_tlsv12(char **args, int cur_arg, struct proxy *px, s
return ERR_ALERT | ERR_FATAL; return ERR_ALERT | ERR_FATAL;
#endif #endif
} }
static int bind_parse_force_tlsv12(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_force_tlsv12(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "no-tls-tickets" bind keyword */ /* parse the "no-tls-tickets" bind keyword */
static int bind_parse_no_tls_tickets(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_no_tls_tickets(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
conf->ssl_options |= BC_SSL_O_NO_TLS_TICKETS; conf->ssl_options |= BC_SSL_O_NO_TLS_TICKETS;
return 0; return 0;
} }
static int bind_parse_no_tls_tickets(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_no_tls_tickets(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "no-sslv3" bind keyword */ /* parse the "no-sslv3" bind keyword */
static int bind_parse_no_sslv3(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_no_sslv3(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
conf->ssl_options |= BC_SSL_O_NO_SSLV3; conf->ssl_options |= BC_SSL_O_NO_SSLV3;
return 0; return 0;
} }
static int bind_parse_no_sslv3(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_no_sslv3(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "no-tlsv10" bind keyword */ /* parse the "no-tlsv10" bind keyword */
static int bind_parse_no_tlsv10(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_no_tlsv10(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
conf->ssl_options |= BC_SSL_O_NO_TLSV10; conf->ssl_options |= BC_SSL_O_NO_TLSV10;
return 0; return 0;
} }
static int bind_parse_no_tlsv10(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_no_tlsv10(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "no-tlsv11" bind keyword */ /* parse the "no-tlsv11" bind keyword */
static int bind_parse_no_tlsv11(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_no_tlsv11(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
conf->ssl_options |= BC_SSL_O_NO_TLSV11; conf->ssl_options |= BC_SSL_O_NO_TLSV11;
return 0; return 0;
} }
static int bind_parse_no_tlsv11(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_no_tlsv11(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "no-tlsv12" bind keyword */ /* parse the "no-tlsv12" bind keyword */
static int bind_parse_no_tlsv12(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_no_tlsv12(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
conf->ssl_options |= BC_SSL_O_NO_TLSV12; conf->ssl_options |= BC_SSL_O_NO_TLSV12;
return 0; return 0;
} }
static int bind_parse_no_tlsv12(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_no_tlsv12(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "npn" bind keyword */ /* parse the "npn" bind keyword */
static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
#ifdef OPENSSL_NPN_NEGOTIATED #ifdef OPENSSL_NPN_NEGOTIATED
char *p1, *p2; char *p1, *p2;
@ -5564,8 +5739,13 @@ static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bin
#endif #endif
} }
static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_npn(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "alpn" bind keyword */ /* parse the "alpn" bind keyword */
static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
char *p1, *p2; char *p1, *p2;
@ -5615,15 +5795,20 @@ static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct bi
#endif #endif
} }
static int bind_parse_alpn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, err);
}
/* parse the "ssl" bind keyword */ /* parse the "ssl" bind keyword */
static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{ {
conf->xprt = &ssl_sock; conf->xprt = &ssl_sock;
conf->is_ssl = 1; conf->is_ssl = 1;
if (global_ssl.listen_default_ciphers && !conf->ciphers) if (global_ssl.listen_default_ciphers && !conf->ssl_conf.ciphers)
conf->ciphers = strdup(global_ssl.listen_default_ciphers); conf->ssl_conf.ciphers = strdup(global_ssl.listen_default_ciphers);
conf->ssl_options |= global_ssl.listen_default_ssloptions; conf->ssl_conf.ssl_options |= global_ssl.listen_default_ssloptions;
return 0; return 0;
} }
@ -5723,7 +5908,7 @@ static int bind_parse_tls_ticket_keys(char **args, int cur_arg, struct proxy *px
} }
/* parse the "verify" bind keyword */ /* parse the "verify" bind keyword */
static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err) static int ssl_bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct ssl_bind_conf *conf, char **err)
{ {
if (!*args[cur_arg + 1]) { if (!*args[cur_arg + 1]) {
if (err) if (err)
@ -5746,6 +5931,10 @@ static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct
return 0; return 0;
} }
static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
return ssl_bind_parse_verify(args, cur_arg, px, &conf->ssl_conf, err);
}
/************** "server" keywords ****************/ /************** "server" keywords ****************/
@ -6620,6 +6809,26 @@ static struct acl_kw_list acl_kws = {ILH, {
* the config parser can report an appropriate error when a known keyword was * the config parser can report an appropriate error when a known keyword was
* not enabled. * not enabled.
*/ */
static struct ssl_bind_kw ssl_bind_kws[] = {
{ "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 */
{ "ciphers", ssl_bind_parse_ciphers, 1 }, /* set SSL cipher suite */
{ "crl-file", ssl_bind_parse_crl_file, 1 }, /* set certificat revocation list file use on client cert verify */
{ "ecdhe", ssl_bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
{ "force-sslv3", ssl_bind_parse_force_sslv3, 0 }, /* force SSLv3 */
{ "force-tlsv10", ssl_bind_parse_force_tlsv10, 0 }, /* force TLSv10 */
{ "force-tlsv11", ssl_bind_parse_force_tlsv11, 0 }, /* force TLSv11 */
{ "force-tlsv12", ssl_bind_parse_force_tlsv12, 0 }, /* force TLSv12 */
{ "no-sslv3", ssl_bind_parse_no_sslv3, 0 }, /* disable SSLv3 */
{ "no-tlsv10", ssl_bind_parse_no_tlsv10, 0 }, /* disable TLSv10 */
{ "no-tlsv11", ssl_bind_parse_no_tlsv11, 0 }, /* disable TLSv11 */
{ "no-tlsv12", ssl_bind_parse_no_tlsv12, 0 }, /* disable TLSv12 */
{ "no-tls-tickets", ssl_bind_parse_no_tls_tickets, 0 }, /* disable session resumption tickets */
{ "npn", ssl_bind_parse_npn, 1 }, /* set NPN supported protocols */
{ "verify", ssl_bind_parse_verify, 1 }, /* set SSL verify method */
{ NULL, NULL, 0 },
};
static struct bind_kw_list bind_kws = { "SSL", { }, { static struct bind_kw_list bind_kws = { "SSL", { }, {
{ "alpn", bind_parse_alpn, 1 }, /* set ALPN supported protocols */ { "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 verify on client cert */