diff --git a/.gitmodules b/.gitmodules index 6f120301..dc06b68a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,6 @@ path = stubby url = https://github.com/getdnsapi/stubby.git branch = develop +[submodule "src/ssl_dane"] + path = src/ssl_dane + url = https://github.com/getdnsapi/ssl_dane diff --git a/configure.ac b/configure.ac index caf2cdf3..4e7f3f62 100644 --- a/configure.ac +++ b/configure.ac @@ -408,7 +408,7 @@ fi AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/bn.h openssl/rsa.h openssl/dsa.h],,, [AC_INCLUDES_DEFAULT]) -AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id HMAC_CTX_new HMAC_CTX_free TLS_client_method DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_min_proto_version OpenSSL_version_num OpenSSL_version]) +AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id HMAC_CTX_new HMAC_CTX_free TLS_client_method DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_min_proto_version OpenSSL_version_num OpenSSL_version SSL_CTX_dane_enable SSL_dane_enable SSL_dane_tlsa_add]) AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_OPENSSL_ERR_H @@ -431,6 +431,28 @@ AC_INCLUDES_DEFAULT ]) fi +AC_MSG_CHECKING([whether we need to compile/link DANE support]) +DANESSL_XTRA_OBJS="" +AC_LANG_PUSH(C) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([ + [#include ] + [#if OPENSSL_VERSION_NUMBER < 0x1000000fL] + [#error "OpenSSL 1.0.0 or higher required for DANE library"] + [#elif defined(HAVE_SSL_DANE_ENABLE)] + [#error "OpenSSL has native DANE support"] + [#elif defined(LIBRESSL_VERSION_NUMBER)] + [#error "dane_ssl library does not work with LibreSSL"] + [#endif] + ],[[]])], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE([USE_DANESSL], [1], [Define this to use DANE functions from the ssl_dane/danessl library.]) + DANESSL_XTRA_OBJS="danessl.lo" + ], + [AC_MSG_RESULT([no])]) +AC_LANG_POP(C) +AC_SUBST(DANESSL_XTRA_OBJS) AC_ARG_ENABLE(sha1, AC_HELP_STRING([--disable-sha1], [Disable SHA1 RRSIG support, does not disable nsec3 support])) case "$enable_sha1" in diff --git a/src/Makefile.in b/src/Makefile.in index 227d683f..983f4fc8 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -96,7 +96,9 @@ JSMN_OBJ=jsmn.lo YXML_OBJ=yxml.lo YAML_OBJ=convert_yaml_to_json.lo -GETDNS_XTRA_OBJS=@GETDNS_XTRA_OBJS@ +DANESSL_OBJ=danessl.lo + +GETDNS_XTRA_OBJS=@GETDNS_XTRA_OBJS@ @DANESSL_XTRA_OBJS@ STUBBY_XTRA_OBJS=@STUBBY_XTRA_OBJS@ EXTENSION_OBJ=$(DEFAULT_EVENTLOOP_OBJ) libevent.lo libev.lo @@ -133,6 +135,9 @@ $(JSMN_OBJ): $(YAML_OBJ): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(stubbysrcdir)/src/yaml/$(@:.lo=.c) -o $@ +$(DANESSL_OBJ): + $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WNOERRORFLAG) -c $(srcdir)/ssl_dane/$(@:.lo=.c) -o $@ + $(YXML_OBJ): $(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -I$(srcdir)/yxml -DYXML_GETDNS -Wno-unused-parameter -c $(srcdir)/yxml/$(@:.lo=.c) -o $@ @@ -255,7 +260,7 @@ Makefile: $(srcdir)/Makefile.in ../config.status depend: (cd $(srcdir) ; awk 'BEGIN{P=1}{if(P)print}/^# Dependencies/{P=0}' Makefile.in > Makefile.in.new ) - (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" -Iyxml -Iutil/auxiliary -I../stubby/src *.c gldns/*.c compat/*.c util/*.c jsmn/*.c yxml/*.c extension/*.c ../stubby/src/*.c | \ + (blddir=`pwd`; cd $(srcdir) ; gcc -MM -I. -I"$$blddir" -Iyxml -Iutil/auxiliary -I../stubby/src *.c gldns/*.c compat/*.c util/*.c jsmn/*.c yxml/*.c ssl_dane/danessl.c extension/*.c ../stubby/src/*.c | \ sed -e "s? $$blddir/? ?g" \ -e 's? gldns/? $$(srcdir)/gldns/?g' \ -e 's? compat/? $$(srcdir)/compat/?g' \ @@ -263,6 +268,7 @@ depend: -e 's? util/? $$(srcdir)/util/?g' \ -e 's? jsmn/? $$(srcdir)/jsmn/?g' \ -e 's? yxml/? $$(srcdir)/yxml/?g' \ + -e 's? ssl_dane/? $$(srcdir)/ssl_dane/?g' \ -e 's? extension/? $$(srcdir)/extension/?g' \ -e 's? \.\./stubby/? $$(stubbysrcdir)/?g' \ -e 's? \([a-z_-]*\)\.\([ch]\)? $$(srcdir)/\1.\2?g' \ @@ -311,7 +317,7 @@ context.lo context.o: $(srcdir)/context.c \ $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h $(srcdir)/util/lruhash.h \ $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/orig-headers/locks.h \ $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/dnssec.h \ - $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h + $(srcdir)/gldns/rrdef.h $(srcdir)/stub.h $(srcdir)/list.h $(srcdir)/dict.h $(srcdir)/pubkey-pinning.h $(srcdir)/ssl_dane/danessl.h convert.lo convert.o: $(srcdir)/convert.c \ config.h \ getdns/getdns.h \ @@ -450,7 +456,7 @@ stub.lo stub.o: $(srcdir)/stub.c \ $(srcdir)/extension/poll_eventloop.h $(srcdir)/types-internal.h $(srcdir)/ub_loop.h $(srcdir)/server.h \ $(srcdir)/util/lruhash.h $(srcdir)/util/orig-headers/lruhash.h $(srcdir)/util/locks.h \ $(srcdir)/util/orig-headers/locks.h $(srcdir)/util/auxiliary/util/log.h $(srcdir)/debug.h $(srcdir)/anchor.h \ - $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h + $(srcdir)/util-internal.h $(srcdir)/platform.h $(srcdir)/general.h $(srcdir)/pubkey-pinning.h $(srcdir)/ssl_dane/danessl.h sync.lo sync.o: $(srcdir)/sync.c \ getdns/getdns.h \ config.h \ @@ -557,6 +563,7 @@ val_secalgo.lo val_secalgo.o: $(srcdir)/util/val_secalgo.c \ $(srcdir)/util/auxiliary/sldns/sbuffer.h $(srcdir)/gldns/gbuffer.h jsmn.lo jsmn.o: $(srcdir)/jsmn/jsmn.c $(srcdir)/jsmn/jsmn.h yxml.lo yxml.o: $(srcdir)/yxml/yxml.c $(srcdir)/yxml/yxml.h +danessl.lo danessl.o: $(srcdir)/ssl_dane/danessl.c $(srcdir)/ssl_dane/danessl.h libev.lo libev.o: $(srcdir)/extension/libev.c \ config.h \ $(srcdir)/types-internal.h \ diff --git a/src/context.c b/src/context.c index c8f14363..7856b690 100644 --- a/src/context.c +++ b/src/context.c @@ -59,6 +59,7 @@ typedef unsigned short in_port_t; #include #include +#include #include #include @@ -89,6 +90,9 @@ typedef unsigned short in_port_t; #include "list.h" #include "dict.h" #include "pubkey-pinning.h" +#ifdef USE_DANESSL +# include "ssl_dane/danessl.h" +#endif #define GETDNS_PORT_ZERO 0 #define GETDNS_PORT_DNS 53 @@ -681,6 +685,27 @@ upstreams_create(getdns_context *context, size_t size) return r; } + +#if defined(USE_DANESSL) && defined(STUB_DEBUG) && STUB_DEBUG +static void _stub_debug_print_openssl_errors(void) +{ + unsigned long err; + char buffer[1024]; + const char *file; + const char *data; + int line; + int flags; + + while ((err = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) { + ERR_error_string_n(err, buffer, sizeof(buffer)); + if (flags & ERR_TXT_STRING) + DEBUG_STUB("DEBUG OpenSSL Error: %s:%s:%d:%s\n", buffer, file, line, data); + else + DEBUG_STUB("DEBUG OpenSSL Error: %s:%s:%d\n", buffer, file, line); + } +} +#endif + void _getdns_upstreams_dereference(getdns_upstreams *upstreams) { @@ -722,6 +747,12 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams) if (upstream->tls_obj != NULL) { SSL_shutdown(upstream->tls_obj); +#ifdef USE_DANESSL +# if defined(STUB_DEBUG) && STUB_DEBUG + _stub_debug_print_openssl_errors(); +# endif + DANESSL_cleanup(upstream->tls_obj); +#endif SSL_free(upstream->tls_obj); } if (upstream->fd != -1) @@ -832,6 +863,12 @@ _getdns_upstream_reset(getdns_upstream *upstream) } if (upstream->tls_obj != NULL) { SSL_shutdown(upstream->tls_obj); +#ifdef USE_DANESSL +# if defined(STUB_DEBUG) && STUB_DEBUG + _stub_debug_print_openssl_errors(); +# endif + DANESSL_cleanup(upstream->tls_obj); +#endif SSL_free(upstream->tls_obj); upstream->tls_obj = NULL; } @@ -1636,6 +1673,9 @@ getdns_context_create_with_extended_memory_functions( #if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL) OpenSSL_add_all_algorithms(); SSL_library_init(); +# ifdef USE_DANESSL + (void) DANESSL_library_init(); +# endif #else OPENSSL_init_crypto( OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS @@ -3622,6 +3662,25 @@ _getdns_context_prepare_for_resolution(getdns_context *context) if (context->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) return GETDNS_RETURN_BAD_CONTEXT; } +# if defined(HAVE_SSL_CTX_DANE_ENABLE) +# if defined(STUB_DEBUG) && STUB_DEBUG + int osr = +# else + (void) +# endif + SSL_CTX_dane_enable(context->tls_ctx); + DEBUG_STUB("%s %-35s: DEBUG: SSL_CTX_dane_enable() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); +# elif defined(USE_DANESSL) +# if defined(STUB_DEBUG) && STUB_DEBUG + int osr = +# else + (void) +# endif + DANESSL_CTX_init(context->tls_ctx); + DEBUG_STUB("%s %-35s: DEBUG: DANESSL_CTX_init() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); +# endif #else /* HAVE_TLS_v1_2 */ if (tls_only_is_in_transports_list(context) == 1) return GETDNS_RETURN_BAD_CONTEXT; diff --git a/src/ssl_dane b/src/ssl_dane new file mode 160000 index 00000000..dd093e58 --- /dev/null +++ b/src/ssl_dane @@ -0,0 +1 @@ +Subproject commit dd093e585a237e0321d303ec35e84c393ef739f4 diff --git a/src/stub.c b/src/stub.c index a9ec8240..3c6e4a8e 100644 --- a/src/stub.c +++ b/src/stub.c @@ -55,6 +55,9 @@ #include "platform.h" #include "general.h" #include "pubkey-pinning.h" +#ifdef USE_DANESSL +# include "ssl_dane/danessl.h" +#endif /* WSA TODO: * STUB_TCP_RETRY added to deal with edge triggered event loops (versus @@ -827,7 +830,37 @@ tls_requested(getdns_network_req *netreq) 1 : 0; } -int + +#if defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) + +static int +_getdns_tls_verify_always_ok(int ok, X509_STORE_CTX *ctx) +{ +# if defined(STUB_DEBUG) && STUB_DEBUG + char buf[8192]; + X509 *cert; + int err; + int depth; + + cert = X509_STORE_CTX_get_current_cert(ctx); + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + if (cert) + X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); + else + strcpy(buf, ""); + DEBUG_STUB("DEBUG Cert verify: depth=%d verify=%d err=%d subject=%s errorstr=%s\n", depth, ok, err, buf, X509_verify_cert_error_string(err)); +# else /* defined(STUB_DEBUG) && STUB_DEBUG */ + (void)ok; + (void)ctx; +# endif /* #else defined(STUB_DEBUG) && STUB_DEBUG */ + return 1; +} + +#else /* defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) */ + +static int tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { getdns_upstream *upstream; @@ -837,36 +870,22 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) return 0; int err = X509_STORE_CTX_get_error(ctx); -#if defined(STUB_DEBUG) && STUB_DEBUG +# if defined(STUB_DEBUG) && STUB_DEBUG DEBUG_STUB("%s %-35s: FD: %d Verify result: (%d) \"%s\"\n", STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, err, X509_verify_cert_error_string(err)); -#endif +# endif if (!preverify_ok && !upstream->tls_fallback_ok) _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR, "%-40s : Verify failed : Transport=TLS - *Failure* - (%d) \"%s\"\n", upstream->addr_str, err, X509_verify_cert_error_string(err)); - /* First deal with the hostname authentication done by OpenSSL. */ -#ifdef X509_V_ERR_HOSTNAME_MISMATCH -# if defined(STUB_DEBUG) && STUB_DEBUG - /*Report if error is hostname mismatch*/ - if (err == X509_V_ERR_HOSTNAME_MISMATCH && upstream->tls_fallback_ok) - DEBUG_STUB("%s %-35s: FD: %d WARNING: Proceeding even though hostname validation failed!\n", - STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd); -# endif -#else - /* if we weren't built against OpenSSL with hostname matching we - * could not have matched the hostname, so this would be an automatic - * tls_auth_fail if there is a hostname provided*/ - if (upstream->tls_auth_name[0]) { - upstream->tls_auth_state = GETDNS_AUTH_FAILED; - preverify_ok = 0; - } -#endif + /* No need to deal with hostname authentication, since this will be + * dealt with in the DANE preprocessor paths. + */ - /* Now deal with the pinset validation*/ + /* Deal with the pinset validation */ if (upstream->tls_pubkey_pinset) pinset_ret = _getdns_verify_pinset_match(upstream->tls_pubkey_pinset, ctx); @@ -882,22 +901,7 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_ERR, "%-40s : Conn failed : Transport=TLS - *Failure* - Pinset validation failure\n", upstream->addr_str); - } else { - /* If we _only_ had a pinset and it is good then force succesful - authentication when the cert self-signed - TODO: We need to check for other error cases here, not blindly accept the cert!! */ - if ((upstream->tls_pubkey_pinset && upstream->tls_auth_name[0] == '\0') && - (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN || - err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) { - preverify_ok = 1; - DEBUG_STUB("%s %-35s: FD: %d, Allowing self-signed (%d) cert since pins match\n", - STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, err); - _getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG, - "%-40s : Verify passed : Transport=TLS - Allowing self-signed cert since pins match\n", - upstream->addr_str); - } } - /* If nothing has failed yet and we had credentials, we have succesfully authenticated*/ if (preverify_ok == 0) upstream->tls_auth_state = GETDNS_AUTH_FAILED; @@ -910,6 +914,8 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) return (upstream->tls_fallback_ok) ? 1 : preverify_ok; } +#endif /* #else defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) */ + static SSL* tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) { @@ -943,7 +949,10 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name); SSL_set_tlsext_host_name(ssl, upstream->tls_auth_name); #ifdef HAVE_SSL_HN_AUTH - /* Set up native OpenSSL hostname verification*/ + /* Set up native OpenSSL hostname verification + * ( doesn't work with USE_DANESSL, but we verify the + * name afterwards in such cases ) + */ X509_VERIFY_PARAM *param; param = SSL_get0_param(ssl); X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); @@ -994,7 +1003,71 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) DEBUG_STUB("%s %-35s: Using Strict TLS \n", STUB_DEBUG_SETUP_TLS, __FUNC__); } +#if defined(HAVE_SSL_DANE_ENABLE) + int osr; +# if defined(STUB_DEBUG) && STUB_DEBUG + osr = +# else + (void) +# endif + SSL_dane_enable(ssl, *upstream->tls_auth_name ? upstream->tls_auth_name : NULL); + DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_enable(\"%s\") -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name, osr); + SSL_set_verify(ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok); + sha256_pin_t *pin_p; + size_t n_pins = 0; + for (pin_p = upstream->tls_pubkey_pinset; pin_p; pin_p = pin_p->next) { + osr = SSL_dane_tlsa_add(ssl, 2, 1, 1, + (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); + DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); + if (osr > 0) + ++n_pins; + osr = SSL_dane_tlsa_add(ssl, 3, 1, 1, + (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); + DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); + if (osr > 0) + ++n_pins; + } +#elif defined(USE_DANESSL) + if (upstream->tls_pubkey_pinset) { + const char *auth_names[2] = { upstream->tls_auth_name, NULL }; + int osr; +# if defined(STUB_DEBUG) && STUB_DEBUG + osr = +# else + (void) +# endif + DANESSL_init(ssl, + *upstream->tls_auth_name ? upstream->tls_auth_name : NULL, + *upstream->tls_auth_name ? auth_names : NULL + ); + DEBUG_STUB("%s %-35s: DEBUG: DANESSL_init(\"%s\") -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->tls_auth_name, osr); + SSL_set_verify(ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok); + sha256_pin_t *pin_p; + size_t n_pins = 0; + for (pin_p = upstream->tls_pubkey_pinset; pin_p; pin_p = pin_p->next) { + osr = DANESSL_add_tlsa(ssl, 3, 1, "sha256", + (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); + DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); + if (osr > 0) + ++n_pins; + osr = DANESSL_add_tlsa(ssl, 2, 1, "sha256", + (unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH); + DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n" + , STUB_DEBUG_SETUP_TLS, __FUNC__, osr); + if (osr > 0) + ++n_pins; + } + } else { + SSL_set_verify(ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok); + } +#else SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback); +#endif SSL_set_connect_state(ssl); (void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); @@ -1011,7 +1084,6 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) __FUNC__); } } - return ssl; } @@ -1050,16 +1122,119 @@ tls_do_handshake(getdns_upstream *upstream) return STUB_SETUP_ERROR; } } - upstream->tls_hs_state = GETDNS_HS_DONE; - upstream->conn_state = GETDNS_CONN_OPEN; - upstream->conn_completed++; /* A re-used session is not verified so need to fix up state in that case */ if (SSL_session_reused(upstream->tls_obj)) upstream->tls_auth_state = upstream->last_tls_auth_state; + +#if defined(USE_DANESSL) || defined(HAVE_SSL_HN_AUTH) + else if (upstream->tls_pubkey_pinset || upstream->tls_auth_name[0]) { + X509 *peer_cert = SSL_get_peer_certificate(upstream->tls_obj); + long verify_result = SSL_get_verify_result(upstream->tls_obj); + +/* In case of DANESSL use, and a tls_auth_name was given alongside a pinset, + * we need to verify auth_name explicitely (otherwise it will not be checked, + * because this is not required with DANE with an EE match). + * This is not needed with native OpenSSL DANE, because EE name checks have + * to be disabled explicitely. + */ +# if defined(USE_DANESSL) && defined(HAVE_SSL_HN_AUTH) + if (peer_cert && verify_result == X509_V_OK + && upstream->tls_auth_name[0] + && upstream->tls_pubkey_pinset + && X509_check_host(peer_cert, upstream->tls_auth_name, 0, + X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS, NULL) <= 0) + verify_result = X509_V_ERR_HOSTNAME_MISMATCH; +# endif + upstream->tls_auth_state = peer_cert && verify_result == X509_V_OK + ? GETDNS_AUTH_OK : GETDNS_AUTH_FAILED; + if (!peer_cert) + _getdns_upstream_log(upstream, + GETDNS_LOG_UPSTREAM_STATS, + ( upstream->tls_fallback_ok + ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), + "%-40s : Verify failed : Transport=TLS - %s - " + "Remote did not offer certificate\n", + upstream->addr_str, + ( upstream->tls_fallback_ok + ? "Tolerated because of Opportunistic profile" + : "*Failure*" )); + + /* Since we don't have DANE validation yet, DANE validation + * failures are always pinset validation failures + */ +# if defined(HAVE_SSL_DANE_ENABLE) + else if (verify_result == X509_V_ERR_DANE_NO_MATCH) + _getdns_upstream_log(upstream, + GETDNS_LOG_UPSTREAM_STATS, + ( upstream->tls_fallback_ok + ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), + "%-40s : Verify failed : Transport=TLS - %s - " + "Pinset validation failure\n", upstream->addr_str, + ( upstream->tls_fallback_ok + ? "Tolerated because of Opportunistic profile" + : "*Failure*" )); +# elif defined(USE_DANESSL) + else if (verify_result == X509_V_ERR_CERT_UNTRUSTED + && upstream->tls_pubkey_pinset + && !DANESSL_get_match_cert( + upstream->tls_obj, NULL, NULL, NULL)) + _getdns_upstream_log(upstream, + GETDNS_LOG_UPSTREAM_STATS, + ( upstream->tls_fallback_ok + ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), + "%-40s : Verify failed : Transport=TLS - %s - " + "Pinset validation failure\n", upstream->addr_str, + ( upstream->tls_fallback_ok + ? "Tolerated because of Opportunistic profile" + : "*Failure*" )); +# endif + else if (verify_result != X509_V_OK) + _getdns_upstream_log(upstream, + GETDNS_LOG_UPSTREAM_STATS, + ( upstream->tls_fallback_ok + ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), + "%-40s : Verify failed : Transport=TLS - %s - " + "(%d) \"%s\"\n", upstream->addr_str, + ( upstream->tls_fallback_ok + ? "Tolerated because of Opportunistic profile" + : "*Failure*" ), verify_result, + X509_verify_cert_error_string(verify_result)); +# ifndef HAVE_SSL_HN_AUTH + else if (*upstream->tls_auth_name) { + _getdns_upstream_log(upstream, + GETDNS_LOG_UPSTREAM_STATS, + ( upstream->tls_fallback_ok + ? GETDNS_LOG_INFO : GETDNS_LOG_ERR), + "%-40s : Verify failed : Transport=TLS - %s - " + "Hostname Authentication not available from TLS " + "library (check library version)\n", + upstream->addr_str, + ( upstream->tls_fallback_ok + ? "Tolerated because of Opportunistic profile" + : "*Failure*" )); + + upstream->tls_auth_state = GETDNS_AUTH_FAILED; + } +# endif + else + _getdns_upstream_log(upstream, + GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG, + "%-40s : Verify passed : Transport=TLS\n", + upstream->addr_str); + + X509_free(peer_cert); + if (upstream->tls_auth_state == GETDNS_AUTH_FAILED + && !upstream->tls_fallback_ok) + return STUB_SETUP_ERROR; + } +#endif /* defined(USE_DANESSL) || defined(HAVE_SSL_HN_AUTH) */ DEBUG_STUB("%s %-35s: FD: %d Handshake succeeded with auth state %s. Session is %s.\n", STUB_DEBUG_SETUP_TLS, __FUNC__, upstream->fd, _getdns_auth_str(upstream->tls_auth_state), SSL_session_reused(upstream->tls_obj) ?"re-used":"new"); + upstream->tls_hs_state = GETDNS_HS_DONE; + upstream->conn_state = GETDNS_CONN_OPEN; + upstream->conn_completed++; if (upstream->tls_session != NULL) SSL_SESSION_free(upstream->tls_session); upstream->tls_session = SSL_get1_session(upstream->tls_obj); diff --git a/src/tools/getdns_query.c b/src/tools/getdns_query.c index 66943900..3102ce1a 100644 --- a/src/tools/getdns_query.c +++ b/src/tools/getdns_query.c @@ -57,19 +57,7 @@ getdns_return_t getdns_yaml2dict(const char *, getdns_dict **dict); #define EXAMPLE_PIN "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"" static int verbosity = 0; -static int i_am_stubby = 0; -static const char *default_stubby_config = -"{ resolution_type: GETDNS_RESOLUTION_STUB" -", dns_transport_list: [ GETDNS_TRANSPORT_TLS, GETDNS_TRANSPORT_UDP, GETDNS_TRANSPORT_TCP ]" -", idle_timeout: 10000" -", listen_addresses: [ 127.0.0.1@53, 0::1@53 ]" -", tls_query_padding_blocksize: 1" -", edns_client_subnet_private : 1" -"}"; static int clear_listen_list_on_arg = 0; -#ifndef GETDNS_ON_WINDOWS -static int run_in_foreground = 1; -#endif static int quiet = 0; static int batch_mode = 0; static char *query_file = NULL; @@ -95,6 +83,8 @@ static int check_dnssec = 0; static char *resolvconf = NULL; #endif static int print_api_info = 0, print_trust_anchors = 0; +static int log_level = 0; +static uint64_t log_systems = 0xFFFFFFFFFFFFFFFF; static int get_rrtype(const char *t) { @@ -179,19 +169,14 @@ print_usage(FILE *out, const char *progname) { fprintf(out, "usage: %s [