- Add SNI support on more TLS connections (fixes #193).

- Add SNI support to unbound-anchor.
This commit is contained in:
George Thessalonikefs 2020-04-16 13:48:47 +02:00
parent 8a87fc6ae7
commit e430e95d30
19 changed files with 3677 additions and 3592 deletions

View file

@ -1815,7 +1815,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
&worker_alloc_cleanup, worker,
cfg->do_udp || cfg->udp_upstream_without_downstream,
worker->daemon->connect_sslctx, cfg->delay_close,
dtenv);
cfg->tls_use_sni, dtenv);
if(!worker->back) {
log_err("could not create outgoing sockets");
worker_delete(worker);

View file

@ -351,6 +351,7 @@ int dt_io_thread_apply_cfg(struct dt_io_thread* dtio, struct config_file *cfg)
log_err("could not setup SSL CTX");
return 0;
}
dtio->tls_use_sni = cfg->tls_use_sni;
#endif /* HAVE_SSL */
}
return 1;
@ -1661,7 +1662,8 @@ static int dtio_setup_ssl(struct dt_io_thread* dtio)
dtio->ssl_handshake_done = 0;
dtio->ssl_brief_read = 0;
if(!set_auth_name_on_ssl(dtio->ssl, dtio->tls_server_name)) {
if(!set_auth_name_on_ssl(dtio->ssl, dtio->tls_server_name,
dtio->tls_use_sni)) {
return 0;
}
return 1;

View file

@ -109,6 +109,8 @@ struct dt_io_thread {
int started;
/** ssl context for the io thread, for tls connections. type SSL_CTX* */
void* ssl_ctx;
/** if SNI will be used for TLS connections. */
int tls_use_sni;
/** file descriptor that the thread writes to */
int fd;

View file

@ -746,6 +746,10 @@ server:
# cipher setting for TLSv1.3
# tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
# Use the SNI extension for TLS connections. Default is yes.
# Changing the value requires a reload.
# tls-use-sni: yes
# Add the secret file for TLS Session Ticket.
# Secret file must be 80 bytes of random data.
# First key use to encrypt and decrypt TLS session tickets.

View file

@ -546,6 +546,11 @@ and that is the default.
Set the list of ciphersuites to allow when serving TLS. This is for newer
TLS 1.3 connections. Use "" for defaults, and that is the default.
.TP
.B tls\-use\-sni: \fI<yes or no>
Enable or disable sending the SNI extension on TLS connections.
Default is yes.
Changing the value requires a reload.
.TP
.B use\-systemd: \fI<yes or no>
Enable or disable systemd socket activation.
Default is no.

View file

@ -238,7 +238,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
ports, numports, cfg->unwanted_threshold,
cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
cfg->delay_close, NULL);
cfg->delay_close, cfg->tls_use_sni, NULL);
w->env->outnet = w->back;
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);

View file

@ -386,7 +386,8 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len)
comm_point_tcp_win_bio_cb(pend->c, pend->c->ssl);
#endif
pend->c->ssl_shake_state = comm_ssl_shake_write;
if(!set_auth_name_on_ssl(pend->c->ssl, w->tls_auth_name)) {
if(!set_auth_name_on_ssl(pend->c->ssl, w->tls_auth_name,
w->outnet->tls_use_sni)) {
pend->c->fd = s;
#ifdef HAVE_SSL
SSL_free(pend->c->ssl);
@ -736,7 +737,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports, size_t unwanted_threshold, int tcp_mss,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
void* sslctx, int delayclose, struct dt_env* dtenv)
void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv)
{
struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network));
@ -752,6 +753,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
outnet->infra = infra;
outnet->rnd = rnd;
outnet->sslctx = sslctx;
outnet->tls_use_sni = tls_use_sni;
#ifdef USE_DNSTAP
outnet->dtenv = dtenv;
#else
@ -2296,6 +2298,11 @@ setup_comm_ssl(struct comm_point* cp, struct outside_network* outnet,
#endif
cp->ssl_shake_state = comm_ssl_shake_write;
/* https verification */
#ifdef HAVE_SSL
if(outnet->tls_use_sni) {
(void)SSL_set_tlsext_host_name(cp->ssl, host);
}
#endif
#ifdef HAVE_SSL_SET1_HOST
if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
/* because we set SSL_VERIFY_PEER, in netevent in

View file

@ -132,6 +132,8 @@ struct outside_network {
struct ub_randstate* rnd;
/** ssl context to create ssl wrapped TCP with DNS connections */
void* sslctx;
/** if SNI will be used for TLS connections */
int tls_use_sni;
#ifdef USE_DNSTAP
/** dnstap environment */
struct dt_env* dtenv;
@ -416,6 +418,7 @@ struct serviced_query {
* @param sslctx: context to create outgoing connections with (if enabled).
* @param delayclose: if not 0, udp sockets are delayed before timeout closure.
* msec to wait on timeouted udp sockets.
* @param tls_use_sni: if SNI is used for TLS connections.
* @param dtenv: environment to send dnstap events with (if enabled).
* @return: the new structure (with no pending answers) or NULL on error.
*/
@ -425,7 +428,7 @@ struct outside_network* outside_network_create(struct comm_base* base,
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports, size_t unwanted_threshold, int tcp_mss,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
void* sslctx, int delayclose, struct dt_env *dtenv);
void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv);
/**
* Delete outside_network structure.

View file

@ -187,6 +187,7 @@ usage(void)
printf("-c file cert file, default %s\n", ROOT_CERT_FILE);
printf("-l list builtin key and cert on stdout\n");
printf("-u name server in https url, default %s\n", URLNAME);
printf("-S use SNI for the https connection\n");
printf("-x path pathname to xml in url, default %s\n", XMLNAME);
printf("-s path pathname to p7s in url, default %s\n", P7SNAME);
printf("-n name signer's subject emailAddress, default %s\n", P7SIGNER);
@ -772,7 +773,7 @@ setup_sslctx(void)
/** initiate TLS on a connection */
static SSL*
TLS_initiate(SSL_CTX* sslctx, int fd)
TLS_initiate(SSL_CTX* sslctx, int fd, const char* urlname, int use_sni)
{
X509* x;
int r;
@ -788,6 +789,9 @@ TLS_initiate(SSL_CTX* sslctx, int fd)
SSL_free(ssl);
return NULL;
}
if(use_sni) {
(void)SSL_set_tlsext_host_name(ssl, urlname);
}
while(1) {
ERR_clear_error();
if( (r=SSL_do_handshake(ssl)) == 1)
@ -1123,7 +1127,7 @@ read_http_result(SSL* ssl)
/** https to an IP addr, return BIO with pathname or NULL */
static BIO*
https_to_ip(struct ip_list* ip, const char* pathname, const char* urlname,
struct ip_list* src)
struct ip_list* src, int use_sni)
{
int fd;
SSL* ssl;
@ -1137,7 +1141,7 @@ https_to_ip(struct ip_list* ip, const char* pathname, const char* urlname,
SSL_CTX_free(sslctx);
return NULL;
}
ssl = TLS_initiate(sslctx, fd);
ssl = TLS_initiate(sslctx, fd, urlname, use_sni);
if(!ssl) {
SSL_CTX_free(sslctx);
fd_close(fd);
@ -1161,11 +1165,12 @@ https_to_ip(struct ip_list* ip, const char* pathname, const char* urlname,
* @param pathname: pathname of file on server to GET.
* @param urlname: name to pass as the virtual host for this request.
* @param src: if nonNULL, source address to bind to.
* @param use_sni: if SNI will be used.
* @return a memory BIO with the file in it.
*/
static BIO*
https(struct ip_list* ip_list, const char* pathname, const char* urlname,
struct ip_list* src)
struct ip_list* src, int use_sni)
{
struct ip_list* ip;
BIO* bio = NULL;
@ -1173,7 +1178,7 @@ https(struct ip_list* ip_list, const char* pathname, const char* urlname,
wipe_ip_usage(ip_list);
while( (ip = pick_random_ip(ip_list)) ) {
ip->used = 1;
bio = https_to_ip(ip, pathname, urlname, src);
bio = https_to_ip(ip, pathname, urlname, src, use_sni);
if(bio) break;
}
if(!bio) {
@ -1929,7 +1934,7 @@ do_certupdate(const char* root_anchor_file, const char* root_cert_file,
const char* urlname, const char* xmlname, const char* p7sname,
const char* p7signer, const char* res_conf, const char* root_hints,
const char* debugconf, const char* srcaddr, int ip4only, int ip6only,
int port)
int port, int use_sni)
{
STACK_OF(X509)* cert;
@ -1963,8 +1968,8 @@ do_certupdate(const char* root_anchor_file, const char* root_cert_file,
#endif
/* fetch the necessary files over HTTPS */
xml = https(ip_list, xmlname, urlname, src);
p7s = https(ip_list, p7sname, urlname, src);
xml = https(ip_list, xmlname, urlname, src, use_sni);
p7s = https(ip_list, p7sname, urlname, src, use_sni);
/* verify and update the root anchor */
verify_and_update_anchor(root_anchor_file, xml, p7s, cert, p7signer);
@ -2235,7 +2240,7 @@ do_root_update_work(const char* root_anchor_file, const char* root_cert_file,
const char* urlname, const char* xmlname, const char* p7sname,
const char* p7signer, const char* res_conf, const char* root_hints,
const char* debugconf, const char* srcaddr, int ip4only, int ip6only,
int force, int res_conf_fallback, int port)
int force, int res_conf_fallback, int port, int use_sni)
{
struct ub_result* dnskey;
int used_builtin = 0;
@ -2278,7 +2283,7 @@ do_root_update_work(const char* root_anchor_file, const char* root_cert_file,
probe_date_allows_certupdate(root_anchor_file)) || force) {
if(do_certupdate(root_anchor_file, root_cert_file, urlname,
xmlname, p7sname, p7signer, res_conf, root_hints,
debugconf, srcaddr, ip4only, ip6only, port))
debugconf, srcaddr, ip4only, ip6only, port, use_sni))
return 1;
return used_builtin;
}
@ -2307,8 +2312,9 @@ int main(int argc, char* argv[])
const char* srcaddr = NULL;
int dolist=0, ip4only=0, ip6only=0, force=0, port = HTTPS_PORT;
int res_conf_fallback = 0;
int use_sni = 0;
/* parse the options */
while( (c=getopt(argc, argv, "46C:FRP:a:b:c:f:hln:r:s:u:vx:")) != -1) {
while( (c=getopt(argc, argv, "46C:FRSP:a:b:c:f:hln:r:s:u:vx:")) != -1) {
switch(c) {
case 'l':
dolist = 1;
@ -2331,6 +2337,9 @@ int main(int argc, char* argv[])
case 'u':
urlname = optarg;
break;
case 'S':
use_sni = 1;
break;
case 'x':
xmlname = optarg;
break;
@ -2397,5 +2406,5 @@ int main(int argc, char* argv[])
return do_root_update_work(root_anchor_file, root_cert_file, urlname,
xmlname, p7sname, p7signer, res_conf, root_hints, debugconf,
srcaddr, ip4only, ip6only, force, res_conf_fallback, port);
srcaddr, ip4only, ip6only, force, res_conf_fallback, port, use_sni);
}

View file

@ -1039,7 +1039,8 @@ outside_network_create(struct comm_base* base, size_t bufsize,
int ATTR_UNUSED(outgoing_tcp_mss),
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param),
int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx),
int ATTR_UNUSED(delayclose), struct dt_env* ATTR_UNUSED(dtenv))
int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni),
struct dt_env* ATTR_UNUSED(dtenv))
{
struct replay_runtime* runtime = (struct replay_runtime*)base;
struct outside_network* outnet = calloc(1,

View file

@ -116,6 +116,7 @@ config_create(void)
cfg->ssl_upstream = 0;
cfg->tls_cert_bundle = NULL;
cfg->tls_win_cert = 0;
cfg->tls_use_sni = 1;
cfg->use_syslog = 1;
cfg->log_identity = NULL; /* changed later with argv[0] */
cfg->log_time_ascii = 0;
@ -507,6 +508,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STRLIST_APPEND("tls-session-ticket-keys:", tls_session_ticket_keys)
else S_STR("tls-ciphers:", tls_ciphers)
else S_STR("tls-ciphersuites:", tls_ciphersuites)
else S_YNO("tls-use-sni:", tls_use_sni)
else S_YNO("interface-automatic:", if_automatic)
else S_YNO("use-systemd:", use_systemd)
else S_YNO("do-daemonize:", do_daemonize)
@ -961,6 +963,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_LST(opt, "tls-session-ticket-keys", tls_session_ticket_keys.first)
else O_STR(opt, "tls-ciphers", tls_ciphers)
else O_STR(opt, "tls-ciphersuites", tls_ciphersuites)
else O_YNO(opt, "tls-use-sni", tls_use_sni)
else O_YNO(opt, "use-systemd", use_systemd)
else O_YNO(opt, "do-daemonize", do_daemonize)
else O_STR(opt, "chroot", chrootdir)

View file

@ -128,6 +128,8 @@ struct config_file {
char* tls_ciphers;
/** TLS chiphersuites (TLSv1.3) */
char* tls_ciphersuites;
/** if SNI is to be used */
int tls_use_sni;
/** outgoing port range number of ports (per thread) */
int outgoing_num_ports;

File diff suppressed because it is too large Load diff

View file

@ -248,6 +248,7 @@ tls-additional-port{COLON} { YDVAR(1, VAR_TLS_ADDITIONAL_PORT) }
tls-session-ticket-keys{COLON} { YDVAR(1, VAR_TLS_SESSION_TICKET_KEYS) }
tls-ciphers{COLON} { YDVAR(1, VAR_TLS_CIPHERS) }
tls-ciphersuites{COLON} { YDVAR(1, VAR_TLS_CIPHERSUITES) }
tls-use-sni{COLON} { YDVAR(1, VAR_TLS_USE_SNI) }
use-systemd{COLON} { YDVAR(1, VAR_USE_SYSTEMD) }
do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) }
interface{COLON} { YDVAR(1, VAR_INTERFACE) }

File diff suppressed because it is too large Load diff

View file

@ -323,16 +323,17 @@ extern int yydebug;
VAR_STREAM_WAIT_SIZE = 529,
VAR_TLS_CIPHERS = 530,
VAR_TLS_CIPHERSUITES = 531,
VAR_IPSET = 532,
VAR_IPSET_NAME_V4 = 533,
VAR_IPSET_NAME_V6 = 534,
VAR_TLS_SESSION_TICKET_KEYS = 535,
VAR_RPZ = 536,
VAR_TAGS = 537,
VAR_RPZ_ACTION_OVERRIDE = 538,
VAR_RPZ_CNAME_OVERRIDE = 539,
VAR_RPZ_LOG = 540,
VAR_RPZ_LOG_NAME = 541
VAR_TLS_USE_SNI = 532,
VAR_IPSET = 533,
VAR_IPSET_NAME_V4 = 534,
VAR_IPSET_NAME_V6 = 535,
VAR_TLS_SESSION_TICKET_KEYS = 536,
VAR_RPZ = 537,
VAR_TAGS = 538,
VAR_RPZ_ACTION_OVERRIDE = 539,
VAR_RPZ_CNAME_OVERRIDE = 540,
VAR_RPZ_LOG = 541,
VAR_RPZ_LOG_NAME = 542
};
#endif
/* Tokens. */
@ -610,16 +611,17 @@ extern int yydebug;
#define VAR_STREAM_WAIT_SIZE 529
#define VAR_TLS_CIPHERS 530
#define VAR_TLS_CIPHERSUITES 531
#define VAR_IPSET 532
#define VAR_IPSET_NAME_V4 533
#define VAR_IPSET_NAME_V6 534
#define VAR_TLS_SESSION_TICKET_KEYS 535
#define VAR_RPZ 536
#define VAR_TAGS 537
#define VAR_RPZ_ACTION_OVERRIDE 538
#define VAR_RPZ_CNAME_OVERRIDE 539
#define VAR_RPZ_LOG 540
#define VAR_RPZ_LOG_NAME 541
#define VAR_TLS_USE_SNI 532
#define VAR_IPSET 533
#define VAR_IPSET_NAME_V4 534
#define VAR_IPSET_NAME_V6 535
#define VAR_TLS_SESSION_TICKET_KEYS 536
#define VAR_RPZ 537
#define VAR_TAGS 538
#define VAR_RPZ_ACTION_OVERRIDE 539
#define VAR_RPZ_CNAME_OVERRIDE 540
#define VAR_RPZ_LOG 541
#define VAR_RPZ_LOG_NAME 542
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@ -629,7 +631,7 @@ union YYSTYPE
char* str;
#line 633 "util/configparser.h"
#line 635 "util/configparser.h"
};
typedef union YYSTYPE YYSTYPE;

View file

@ -170,7 +170,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_ALLOW_NOTIFY VAR_TLS_WIN_CERT VAR_TCP_CONNECTION_LIMIT
%token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY
%token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY
%token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES
%token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES VAR_TLS_USE_SNI
%token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6
%token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE
%token VAR_RPZ_CNAME_OVERRIDE VAR_RPZ_LOG VAR_RPZ_LOG_NAME
@ -277,7 +277,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_tcp_connection_limit | server_log_servfail | server_deny_any |
server_unknown_server_time_limit | server_log_tag_queryreply |
server_stream_wait_size | server_tls_ciphers |
server_tls_ciphersuites | server_tls_session_ticket_keys
server_tls_ciphersuites | server_tls_session_ticket_keys |
server_tls_use_sni
;
stubstart: VAR_STUB_ZONE
{
@ -952,6 +953,15 @@ server_tls_session_ticket_keys: VAR_TLS_SESSION_TICKET_KEYS STRING_ARG
yyerror("out of memory");
}
;
server_tls_use_sni: VAR_TLS_USE_SNI STRING_ARG
{
OUTYY(("P(server_tls_use_sni:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->tls_use_sni = (strcmp($2, "yes")==0);
free($2);
}
;
server_use_systemd: VAR_USE_SYSTEMD STRING_ARG
{
OUTYY(("P(server_use_systemd:%s)\n", $2));

View file

@ -1231,11 +1231,13 @@ int check_auth_name_for_ssl(char* auth_name)
}
/** set the authname on an SSL structure, SSL* ssl */
int set_auth_name_on_ssl(void* ssl, char* auth_name)
int set_auth_name_on_ssl(void* ssl, char* auth_name, int use_sni)
{
if(!auth_name) return 1;
#ifdef HAVE_SSL
(void)SSL_set_tlsext_host_name(ssl, auth_name);
if(use_sni) {
(void)SSL_set_tlsext_host_name(ssl, auth_name);
}
#else
(void)ssl;
#endif

View file

@ -453,9 +453,10 @@ int check_auth_name_for_ssl(char* auth_name);
* set auth name on SSL for verification
* @param ssl: SSL* to set
* @param auth_name: if NULL nothing happens, otherwise the name to check.
* @param use_sni: if SNI will be used.
* @return 1 on success or NULL auth_name, 0 on failure.
*/
int set_auth_name_on_ssl(void* ssl, char* auth_name);
int set_auth_name_on_ssl(void* ssl, char* auth_name, int use_sni);
/**
* Initialize openssl locking for thread safety