Use danessl submodule when OpenSSL version between 1.0.0 and 1.1.0

This commit is contained in:
Willem Toorop 2018-01-10 12:47:14 +01:00
parent a1e5cc44a0
commit 7c5bdd5431
4 changed files with 185 additions and 48 deletions

View File

@ -431,6 +431,26 @@ 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 <openssl/opensslv.h>]
[#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"]
[#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

View File

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

View File

@ -59,6 +59,7 @@ typedef unsigned short in_port_t;
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <sys/stat.h>
#include <string.h>
@ -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(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,10 +3662,24 @@ _getdns_context_prepare_for_resolution(getdns_context *context)
if (context->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED)
return GETDNS_RETURN_BAD_CONTEXT;
}
# ifdef HAVE_SSL_CTX_DANE_ENABLE
int osr = SSL_CTX_dane_enable(context->tls_ctx);
# 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)

View File

@ -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
@ -828,13 +831,34 @@ tls_requested(getdns_network_req *netreq)
}
#ifdef HAVE_SSL_DANE_ENABLE
#if defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL)
static int
_getdns_tls_verify_always_ok(int preverify_ok, X509_STORE_CTX *ctx)
{ (void)preverify_ok; (void)ctx; return 1; }
_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;
#else
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, "<unknown>");
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)
@ -857,25 +881,11 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
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);
@ -891,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;
@ -919,7 +914,7 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
return (upstream->tls_fallback_ok) ? 1 : preverify_ok;
}
#endif /* HAVE_SSL_DANE_ENABLE */
#endif /* #else defined(HAVE_SSL_DANE_ENABLE) || defined(USE_DANESSL) */
static SSL*
tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
@ -954,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);
@ -1003,7 +1001,7 @@ 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__);
}
#ifdef HAVE_SSL_DANE_ENABLE
#if defined(HAVE_SSL_DANE_ENABLE)
int osr = 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);
@ -1024,6 +1022,35 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
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 = 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
@ -1043,7 +1070,6 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
__FUNC__);
}
}
return ssl;
}
@ -1086,14 +1112,27 @@ tls_do_handshake(getdns_upstream *upstream)
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;
X509_free(peer_cert);
if (!peer_cert)
_getdns_upstream_log(upstream,
GETDNS_LOG_UPSTREAM_STATS,
@ -1103,7 +1142,7 @@ tls_do_handshake(getdns_upstream *upstream)
"Remote did not offer certificate\n",
upstream->addr_str,
( upstream->tls_fallback_ok
? "Allowed because of Opportunistic profile"
? "Tolerated because of Opportunistic profile"
: "*Failure*" ));
else if (verify_result != X509_V_OK)
@ -1114,15 +1153,33 @@ tls_do_handshake(getdns_upstream *upstream)
"%-40s : Verify failed : Transport=TLS - %s - "
"(%d) \"%s\"\n", upstream->addr_str,
( upstream->tls_fallback_ok
? "Allowed because of Opportunistic profile"
? "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;
@ -1146,6 +1203,7 @@ tls_do_handshake(getdns_upstream *upstream)
NULL, upstream_write_cb, NULL));
return 0;
}
#endif /* defined(USE_DANESSL) || defined(HAVE_SSL_HN_AUTH) */
static int
tls_connected(getdns_upstream* upstream)