mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-11 03:31:36 +00:00
MEDIUM: ssl: add support for the "npn" bind keyword
The ssl_npn match could not work by itself because clients do not use the NPN extension unless the server advertises the protocols it supports. Thanks to Simone Bordet for the explanations on how to get it right.
This commit is contained in:
parent
338a4fc2a8
commit
6c9a3d5585
@ -6958,6 +6958,13 @@ no-tlsv12
|
||||
cannot be enabled using any configuration option. See also "force-tls*",
|
||||
and "force-sslv3".
|
||||
|
||||
npn <protocols>
|
||||
This enables the NPN TLS extension and advertises the specified protocol list
|
||||
as supported on top of NPN. The protocol list consists in a comma-delimited
|
||||
list of protocol names, for instance: "http/1.1,http/1.0" (without quotes).
|
||||
This requires that the SSL library is build with support for TLS extensions
|
||||
enabled (check with haproxy -vv).
|
||||
|
||||
ssl
|
||||
This setting is only available when support for OpenSSL was built in. It
|
||||
enables SSL deciphering on connections instanciated from this listener. A
|
||||
@ -8344,6 +8351,9 @@ ssl_npn <string>
|
||||
layer which deciphered it and found a Next Protocol Negociation TLS extension
|
||||
sent by the client, matching the specified string. This requires that the SSL
|
||||
library is build with support for TLS extensions enabled (check haproxy -vv).
|
||||
Note that the TLS NPN extension is not advertised unless the "npn" keyword on
|
||||
the "bind" line specifies a protocol list. Also, nothing forces the client to
|
||||
pick a protocol from this list, any other one may be requested.
|
||||
|
||||
ssl_sni <string>
|
||||
Returns true when the incoming connection was made over an SSL/TLS transport
|
||||
|
@ -122,6 +122,8 @@ struct bind_conf {
|
||||
int ssl_options; /* ssl options */
|
||||
int verify; /* verify method (set of SSL_VERIFY_* flags) */
|
||||
SSL_CTX *default_ctx; /* SSL context of first/default certificate */
|
||||
char *npn_str; /* NPN protocol string */
|
||||
int npn_len; /* NPN protocol string length */
|
||||
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 */
|
||||
#endif
|
||||
|
@ -141,6 +141,21 @@ int ssl_sock_verifycbk(int ok, X509_STORE_CTX *x_store)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||
/* This callback is used so that the server advertises the list of
|
||||
* negociable protocols for NPN.
|
||||
*/
|
||||
static int ssl_sock_advertise_npn_protos(SSL *s, const unsigned char **data,
|
||||
unsigned int *len, void *arg)
|
||||
{
|
||||
struct bind_conf *conf = arg;
|
||||
|
||||
*data = (const unsigned char *)conf->npn_str;
|
||||
*len = conf->npn_len;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
/* Sets the SSL ctx of <ssl> to match the advertised server name. Returns a
|
||||
* warning when no match is found, which implies the default (first) cert
|
||||
@ -548,6 +563,11 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy
|
||||
}
|
||||
|
||||
SSL_CTX_set_info_callback(ctx, ssl_sock_infocbk);
|
||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||
if (bind_conf->npn_str)
|
||||
SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_sock_advertise_npn_protos, bind_conf);
|
||||
#endif
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_sock_switchctx_cbk);
|
||||
SSL_CTX_set_tlsext_servername_arg(ctx, bind_conf);
|
||||
@ -1118,11 +1138,11 @@ smp_fetch_has_sni(struct proxy *px, struct session *l4, void *l7, unsigned int o
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||
static int
|
||||
smp_fetch_ssl_npn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
|
||||
const struct arg *args, struct sample *smp)
|
||||
{
|
||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||
smp->flags = 0;
|
||||
smp->type = SMP_T_CSTR;
|
||||
|
||||
@ -1137,10 +1157,8 @@ smp_fetch_ssl_npn(struct proxy *px, struct session *l4, void *l7, unsigned int o
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
smp_fetch_ssl_sni(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
|
||||
@ -1466,6 +1484,54 @@ static int bind_parse_no_tlsv12(char **args, int cur_arg, struct proxy *px, stru
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse the "npn" bind keyword */
|
||||
static int bind_parse_npn(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
||||
{
|
||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||
char *p1, *p2;
|
||||
|
||||
if (!*args[cur_arg + 1]) {
|
||||
memprintf(err, "'%s' : missing the comma-delimited NPN protocol suite", args[cur_arg]);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
free(conf->npn_str);
|
||||
|
||||
/* the NPN string is built as a suite of (<len> <name>)* */
|
||||
conf->npn_len = strlen(args[cur_arg + 1]) + 1;
|
||||
conf->npn_str = calloc(1, conf->npn_len);
|
||||
memcpy(conf->npn_str + 1, args[cur_arg + 1], conf->npn_len);
|
||||
|
||||
/* replace commas with the name length */
|
||||
p1 = conf->npn_str;
|
||||
p2 = p1 + 1;
|
||||
while (1) {
|
||||
p2 = memchr(p1 + 1, ',', conf->npn_str + conf->npn_len - (p1 + 1));
|
||||
if (!p2)
|
||||
p2 = p1 + 1 + strlen(p1 + 1);
|
||||
|
||||
if (p2 - (p1 + 1) > 255) {
|
||||
*p2 = '\0';
|
||||
memprintf(err, "'%s' : NPN protocol name too long : '%s'", args[cur_arg], p1 + 1);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
*p1 = p2 - (p1 + 1);
|
||||
p1 = p2;
|
||||
|
||||
if (!*p2)
|
||||
break;
|
||||
|
||||
*(p2++) = '\0';
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
if (err)
|
||||
memprintf(err, "'%s' : library does not support TLS NPN extension", args[cur_arg]);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* parse the "ssl" bind keyword */
|
||||
static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
||||
{
|
||||
@ -1743,6 +1809,7 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
|
||||
{ "no-tls-tickets", bind_parse_no_tls_tickets, 0 }, /* disable session resumption tickets */
|
||||
{ "ssl", bind_parse_ssl, 0 }, /* enable SSL processing */
|
||||
{ "verify", bind_parse_verify, 1 }, /* set SSL verify method */
|
||||
{ "npn", bind_parse_npn, 1 }, /* set NPN supported protocols */
|
||||
{ NULL, NULL, 0 },
|
||||
}};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user