mirror of https://github.com/getdnsapi/getdns.git
Merge remote-tracking branch 'sara/feature/tls_auth_api' into features/tls_auth_api
This commit is contained in:
commit
3cc44ffcb1
|
@ -3,6 +3,12 @@
|
|||
(ldns still necessary to be able to run tests though)
|
||||
* Bugfix: DNSSEC code finding zone cut with redirects + pursuing unsigned
|
||||
DS answers close to the root. Thanks Theogene Bucuti!
|
||||
* Default port for TLS changed to 853
|
||||
* Unofficial extension to the API to allow TLS hostname verification to be
|
||||
required for stub mode when using only TLS as a transport.
|
||||
When required a hostname must be supplied in the
|
||||
'hostname' field of the upstream_list dict and the TLS cipher suites are
|
||||
restricted to the 4 AEAD suites recommended in RFC7525.
|
||||
|
||||
* 2015-09-09: Version 0.3.3
|
||||
* Fix clearing upstream events on shutdown
|
||||
|
|
|
@ -87,7 +87,7 @@ External dependencies are linked outside the getdns API build tree (we rely on c
|
|||
|
||||
* [libunbound from NLnet Labs](http://www.nlnetlabs.nl/projects/unbound/) version 1.4.16 or later
|
||||
* [libidn from the FSF](http://www.gnu.org/software/libidn/) version 1.
|
||||
* [libssl from the OpenSSL Project](https://www.openssl.org/) version 0.9.7 or later. (Note: version 1.0.2 or later is required for TLS support)
|
||||
* [libssl from the OpenSSL Project](https://www.openssl.org/) version 0.9.7 or later. (Note: version 1.0.1 or later is required for TLS support, version 1.0.2 or later is required for TLS hostname authentication)
|
||||
* Doxygen is used to generate documentation, while this is not technically necessary for the build it makes things a lot more pleasant.
|
||||
|
||||
You have to install the library and also the library-devel (or -dev) for your
|
||||
|
@ -226,7 +226,7 @@ To install the [event loop integration libraries](https://github.com/getdnsapi/g
|
|||
|
||||
Note that in order to compile the examples, the `--with-libevent` switch is required.
|
||||
|
||||
As of the 0.2.0 release, when installing via Homebrew, the trust anchor is expected to be located at `$(brew --prefix)/etc/getdns-root.key`. Additionally, the OpenSSL library installed by Homebrew is linked against. Note that the Homebrew OpenSSL installation clones the Keychain certificates to the default OpenSSL location so TLS authentication should work out of the box.
|
||||
As of the 0.2.0 release, when installing via Homebrew, the trust anchor is expected to be located at `$(brew --prefix)/etc/getdns-root.key`. Additionally, the OpenSSL library installed by Homebrew is linked against. Note that the Homebrew OpenSSL installation clones the Keychain certificates to the default OpenSSL location so TLS certificate authentication should work out of the box.
|
||||
|
||||
Contributors
|
||||
============
|
||||
|
|
|
@ -105,10 +105,15 @@ AC_DEFUN([ACX_SSL_CHECKS], [
|
|||
AC_CHECK_HEADERS([openssl/ssl.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([openssl/err.h],,, [AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_HEADERS([openssl/rand.h],,, [AC_INCLUDES_DEFAULT])
|
||||
dnl Authentication now requires 1.0.2, which supports TLSv1.2
|
||||
AC_CHECK_LIB(ssl, SSL_CTX_get0_param,AC_DEFINE([HAVE_LIBSSL_102], [1],
|
||||
[Define if you have libssl 1.0.2 or later]),[AC_MSG_WARN([libssl 1.0.2 or higher is required for TLS authentication. TLS will not be available.])])
|
||||
])dnl End of ACX_SSL_CHECKS
|
||||
|
||||
dnl TLS v1.2 requires OpenSSL 1.0.1
|
||||
AC_CHECK_LIB(ssl, TLSv1_2_client_method,AC_DEFINE([HAVE_TLS_v1_2], [1],
|
||||
[Define if you have libssl with tls 1.2]),[AC_MSG_WARN([Cannot find TLSv1_2_client_method in libssl library. TLS will not be available.])])
|
||||
|
||||
dnl Native OpenSSL hostname verification requires OpenSSL 1.0.2
|
||||
AC_CHECK_LIB(ssl, SSL_CTX_get0_param,AC_DEFINE([HAVE_SSL_HN_AUTH], [1],
|
||||
[Define if you have libssl with host name verification]),[AC_MSG_WARN([Cannot find SSL_CTX_get0_param in libssl library. TLS hostname verification will not be available.])])
|
||||
])
|
||||
|
||||
dnl Check for SSL, where SSL is mandatory
|
||||
dnl Adds --with-ssl option, searches for openssl and defines HAVE_SSL if found
|
||||
|
|
|
@ -84,6 +84,8 @@ static struct const_info consts_info[] = {
|
|||
{ 1201, "GETDNS_TRANSPORT_TCP", GETDNS_TRANSPORT_TCP_TEXT },
|
||||
{ 1202, "GETDNS_TRANSPORT_TLS", GETDNS_TRANSPORT_TLS_TEXT },
|
||||
{ 1203, "GETDNS_TRANSPORT_STARTTLS", GETDNS_TRANSPORT_STARTTLS_TEXT },
|
||||
{ 1300, "GETDNS_AUTHENTICATION_NONE", GETDNS_AUTHENTICATION_NONE_TEXT },
|
||||
{ 1301, "GETDNS_AUTHENTICATION_HOSTNAME", GETDNS_AUTHENTICATION_HOSTNAME_TEXT },
|
||||
};
|
||||
|
||||
static int const_info_cmp(const void *a, const void *b)
|
||||
|
|
|
@ -56,10 +56,10 @@
|
|||
|
||||
#define GETDNS_PORT_ZERO 0
|
||||
#define GETDNS_PORT_DNS 53
|
||||
#define GETDNS_PORT_DNS_OVER_TLS 1021
|
||||
#define GETDNS_PORT_DNS_OVER_TLS 853
|
||||
#define GETDNS_STR_PORT_ZERO "0"
|
||||
#define GETDNS_STR_PORT_DNS "53"
|
||||
#define GETDNS_STR_PORT_DNS_OVER_TLS "1021"
|
||||
#define GETDNS_STR_PORT_DNS_OVER_TLS "853"
|
||||
|
||||
void *plain_mem_funcs_user_arg = MF_PLAIN;
|
||||
|
||||
|
@ -567,8 +567,10 @@ _getdns_upstream_shutdown(getdns_upstream *upstream)
|
|||
upstream->tcp.write_error = 0;
|
||||
upstream->writes_done = 0;
|
||||
upstream->responses_received = 0;
|
||||
if (upstream->tls_hs_state != GETDNS_HS_FAILED)
|
||||
if (upstream->tls_hs_state != GETDNS_HS_FAILED) {
|
||||
upstream->tls_hs_state = GETDNS_HS_NONE;
|
||||
upstream->tls_auth_failed = 0;
|
||||
}
|
||||
/* Now TLS stuff*/
|
||||
if (upstream->tls_obj != NULL) {
|
||||
SSL_shutdown(upstream->tls_obj);
|
||||
|
@ -627,6 +629,7 @@ upstream_init(getdns_upstream *upstream,
|
|||
upstream->starttls_req = NULL;
|
||||
upstream->transport = GETDNS_TRANSPORT_TCP;
|
||||
upstream->tls_hs_state = GETDNS_HS_NONE;
|
||||
upstream->tls_auth_failed = 0;
|
||||
upstream->tls_auth_name[0] = '\0';
|
||||
upstream->tcp.write_error = 0;
|
||||
upstream->loop = NULL;
|
||||
|
@ -897,6 +900,8 @@ getdns_context_create_with_extended_memory_functions(
|
|||
result->edns_maximum_udp_payload_size = -1;
|
||||
if ((r = create_default_dns_transports(result)))
|
||||
goto error;
|
||||
result->tls_auth = GETDNS_AUTHENTICATION_NONE;
|
||||
result->tls_auth_min = GETDNS_AUTHENTICATION_NONE;
|
||||
result->limit_outstanding_queries = 0;
|
||||
result->return_dnssec_status = GETDNS_EXTENSION_FALSE;
|
||||
|
||||
|
@ -1257,8 +1262,7 @@ getdns_set_base_dns_transports(
|
|||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
if (!(new_transports = GETDNS_XMALLOC(context->my_mf,
|
||||
getdns_transport_list_t, transport_count)))
|
||||
|
||||
getdns_transport_list_t, transport_count)))
|
||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||
|
||||
if (context->dns_transports)
|
||||
|
@ -1269,7 +1273,6 @@ getdns_set_base_dns_transports(
|
|||
memcpy(context->dns_transports, transports,
|
||||
transport_count * sizeof(getdns_transport_list_t));
|
||||
context->dns_transport_count = transport_count;
|
||||
dispatch_updated(context, GETDNS_CONTEXT_CODE_NAMESPACES);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
}
|
||||
|
@ -1418,6 +1421,26 @@ getdns_context_set_dns_transport_list(getdns_context *context,
|
|||
return GETDNS_RETURN_GOOD;
|
||||
} /* getdns_context_set_dns_transport_list */
|
||||
|
||||
/*
|
||||
* getdns_context_set_tls_authentication
|
||||
*
|
||||
*/
|
||||
getdns_return_t
|
||||
getdns_context_set_tls_authentication(getdns_context *context,
|
||||
getdns_tls_authentication_t value)
|
||||
{
|
||||
RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
|
||||
if (value != GETDNS_AUTHENTICATION_NONE &&
|
||||
value != GETDNS_AUTHENTICATION_HOSTNAME) {
|
||||
return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
|
||||
}
|
||||
context->tls_auth = value;
|
||||
|
||||
dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION);
|
||||
|
||||
return GETDNS_RETURN_GOOD;
|
||||
} /* getdns_context_set_tls_authentication_list */
|
||||
|
||||
static void
|
||||
set_ub_limit_outstanding_queries(struct getdns_context* context, uint16_t value) {
|
||||
/* num-queries-per-thread */
|
||||
|
@ -2173,20 +2196,38 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context,
|
|||
}
|
||||
|
||||
/* Transport can in theory be set per query in stub mode */
|
||||
if (context->resolution_type == GETDNS_RESOLUTION_STUB) {
|
||||
if (tls_is_in_transports_list(context) == 1 &&
|
||||
context->tls_ctx == NULL) {
|
||||
#ifdef HAVE_LIBSSL_102
|
||||
if (context->resolution_type == GETDNS_RESOLUTION_STUB &&
|
||||
tls_is_in_transports_list(context) == 1) {
|
||||
if (context->tls_ctx == NULL) {
|
||||
#ifdef HAVE_TLS_v1_2
|
||||
/* Create client context, use TLS v1.2 only for now */
|
||||
context->tls_ctx = SSL_CTX_new(TLSv1_2_client_method());
|
||||
#endif
|
||||
if(context->tls_ctx == NULL)
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
SSL_CTX_set_verify(context->tls_ctx, SSL_VERIFY_PEER, NULL);
|
||||
/* Be strict and only use the cipher suites recommended in RFC7525
|
||||
Unless we later fallback to oppotunistic. */
|
||||
const char* const PREFERRED_CIPHERS = "EECDH+aRSA+AESGCM:EDH+aRSA+AESGCM";
|
||||
if (!SSL_CTX_set_cipher_list(context->tls_ctx, PREFERRED_CIPHERS))
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
if (!SSL_CTX_set_default_verify_paths(context->tls_ctx))
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
#else
|
||||
if (tls_only_is_in_transports_list(context) == 1)
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
/* A null tls_ctx will make TLS fail and fallback to the other
|
||||
transports will kick-in.*/
|
||||
#endif
|
||||
}
|
||||
if (tls_only_is_in_transports_list(context) == 1 &&
|
||||
context->tls_auth == GETDNS_AUTHENTICATION_HOSTNAME) {
|
||||
context->tls_auth_min = GETDNS_AUTHENTICATION_HOSTNAME;
|
||||
/* TODO: If no auth data provided for any upstream, fail here */
|
||||
}
|
||||
else {
|
||||
context->tls_auth_min = GETDNS_AUTHENTICATION_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Block use of STARTTLS/TLS ONLY in recursive mode as it won't work */
|
||||
/* Note: If TLS is used in recursive mode this will try TLS on port
|
||||
* 53 so it is blocked here. So is 'STARTTLS only' at the moment. */
|
||||
|
|
|
@ -102,6 +102,7 @@ typedef struct getdns_upstream {
|
|||
getdns_eventloop *loop;
|
||||
getdns_tcp_state tcp;
|
||||
char tls_auth_name[256];
|
||||
size_t tls_auth_failed;
|
||||
|
||||
/* Pipelining of TCP network requests */
|
||||
getdns_network_req *write_queue;
|
||||
|
@ -145,6 +146,8 @@ struct getdns_context {
|
|||
getdns_upstreams *upstreams;
|
||||
uint16_t limit_outstanding_queries;
|
||||
uint32_t dnssec_allowed_skew;
|
||||
getdns_tls_authentication_t tls_auth; /* What user requested for TLS*/
|
||||
getdns_tls_authentication_t tls_auth_min; /* Derived minimum auth allowed*/
|
||||
|
||||
getdns_transport_list_t *dns_transports;
|
||||
size_t dns_transport_count;
|
||||
|
|
|
@ -208,6 +208,23 @@ typedef enum getdns_transport_list_t {
|
|||
*/
|
||||
|
||||
|
||||
/* Authentication options used when doing TLS */
|
||||
typedef enum getdns_tls_authentication_t {
|
||||
GETDNS_AUTHENTICATION_NONE = 1300,
|
||||
GETDNS_AUTHENTICATION_HOSTNAME = 1301,
|
||||
} getdns_tls_authentication_t;
|
||||
|
||||
/**
|
||||
* \defgroup Base authentication texts
|
||||
* @{
|
||||
*/
|
||||
#define GETDNS_AUTHENTICATION_NONE_TEXT "See getdns_context_set_tls_authentication()"
|
||||
#define GETDNS_AUTHENTICATION_HOSTNAME_TEXT "See getdns_context_set_tls_authentication()"
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* Suffix appending methods */
|
||||
typedef enum getdns_append_name_t {
|
||||
GETDNS_APPEND_NAME_ALWAYS = 550,
|
||||
|
@ -247,7 +264,8 @@ typedef enum getdns_context_code_t {
|
|||
GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW = 614,
|
||||
GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS = 615,
|
||||
GETDNS_CONTEXT_CODE_TIMEOUT = 616,
|
||||
GETDNS_CONTEXT_CODE_IDLE_TIMEOUT = 617
|
||||
GETDNS_CONTEXT_CODE_IDLE_TIMEOUT = 617,
|
||||
GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION = 618
|
||||
} getdns_context_code_t;
|
||||
|
||||
/**
|
||||
|
@ -272,6 +290,7 @@ typedef enum getdns_context_code_t {
|
|||
#define GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS_TEXT "Change related to getdns_context_set_memory_functions"
|
||||
#define GETDNS_CONTEXT_CODE_TIMEOUT_TEXT "Change related to getdns_context_set_timeout"
|
||||
#define GETDNS_CONTEXT_CODE_IDLE_TIMEOUT_TEXT "Change related to getdns_context_set_idle_timeout"
|
||||
#define GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION_TEXT "Change related to getdns_context_set_tls_authentication"
|
||||
/** @}
|
||||
*/
|
||||
|
||||
|
@ -347,6 +366,7 @@ typedef enum getdns_callback_type_t {
|
|||
/** @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* \defgroup rrtypes RR Types
|
||||
* @{
|
||||
|
@ -975,6 +995,10 @@ getdns_return_t
|
|||
getdns_context_set_dns_transport_list(getdns_context *context,
|
||||
size_t transport_count, getdns_transport_list_t *transports);
|
||||
|
||||
getdns_return_t
|
||||
getdns_context_set_tls_authentication(getdns_context *context,
|
||||
getdns_tls_authentication_t value);
|
||||
|
||||
getdns_return_t
|
||||
getdns_context_set_idle_timeout(getdns_context *context, uint64_t timeout);
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ getdns_context_set_resolution_type
|
|||
getdns_context_set_return_dnssec_status
|
||||
getdns_context_set_suffix
|
||||
getdns_context_set_timeout
|
||||
getdns_context_set_tls_authentication
|
||||
getdns_context_set_update_callback
|
||||
getdns_context_set_upstream_recursive_servers
|
||||
getdns_context_set_use_threads
|
||||
|
|
|
@ -104,6 +104,7 @@ network_req_init(getdns_network_req *net_req, getdns_dns_req *owner,
|
|||
net_req->transport_current = 0;
|
||||
memcpy(net_req->transports, owner->context->dns_transports,
|
||||
net_req->transport_count * sizeof(getdns_transport_list_t));
|
||||
net_req->tls_auth_min = owner->context->tls_auth_min;
|
||||
memset(&net_req->event, 0, sizeof(net_req->event));
|
||||
memset(&net_req->tcp, 0, sizeof(net_req->tcp));
|
||||
net_req->query_id = 0;
|
||||
|
|
125
src/stub.c
125
src/stub.c
|
@ -32,6 +32,7 @@
|
|||
*/
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include "config.h"
|
||||
#include <fcntl.h>
|
||||
|
@ -563,7 +564,7 @@ upstream_tls_timeout_cb(void *userarg)
|
|||
tls_cleanup(upstream);
|
||||
|
||||
/* Need to handle the case where the far end doesn't respond to a
|
||||
* TCP SYN and doesn't do a reset (as is the case with e.g. 8.8.8.8@1021).
|
||||
* TCP SYN and doesn't do a reset (as is the case with e.g. 8.8.8.8@853).
|
||||
* For that case the socket never becomes writable so doesn't trigger any
|
||||
* callbacks. If so then clear out the queue in one go.*/
|
||||
int ret;
|
||||
|
@ -590,7 +591,7 @@ stub_tls_timeout_cb(void *userarg)
|
|||
tls_cleanup(upstream);
|
||||
|
||||
/* Need to handle the case where the far end doesn't respond to a
|
||||
* TCP SYN and doesn't do a reset (as is the case with e.g. 8.8.8.8@1021).
|
||||
* TCP SYN and doesn't do a reset (as is the case with e.g. 8.8.8.8@853).
|
||||
* For that case the socket never becomes writable so doesn't trigger any
|
||||
* callbacks. If so then clear out the queue in one go.*/
|
||||
int ret;
|
||||
|
@ -819,19 +820,50 @@ tls_failed(getdns_upstream *upstream)
|
|||
/* No messages should be scheduled onto an upstream in this state */
|
||||
return ((upstream->transport == GETDNS_TRANSPORT_TLS ||
|
||||
upstream->transport == GETDNS_TRANSPORT_STARTTLS) &&
|
||||
upstream->tls_hs_state == GETDNS_HS_FAILED) ? 1: 0;
|
||||
upstream->tls_hs_state == GETDNS_HS_FAILED) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tls_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) {
|
||||
return (netreq->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME &&
|
||||
upstream->tls_auth_failed) ? 0 : 1;
|
||||
}
|
||||
|
||||
int
|
||||
tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
int err;
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
const char * err_str;
|
||||
err_str = X509_verify_cert_error_string(err);
|
||||
DEBUG_STUB("--- %s, VERIFY RESULT: %s\n", __FUNCTION__, err_str);
|
||||
/*Always proceed without changing result*/
|
||||
return preverify_ok;
|
||||
}
|
||||
|
||||
int
|
||||
tls_verify_callback_with_fallback(int preverify_ok, X509_STORE_CTX *ctx) {
|
||||
int err;
|
||||
err = X509_STORE_CTX_get_error(ctx);
|
||||
const char * err_str;
|
||||
err_str = X509_verify_cert_error_string(err);
|
||||
DEBUG_STUB("--- %s, VERIFY RESULT: (%d) \"%s\"\n", __FUNCTION__, err, err_str);
|
||||
/*Proceed if error is hostname mismatch*/
|
||||
if (err == X509_V_ERR_HOSTNAME_MISMATCH) {
|
||||
DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return preverify_ok;
|
||||
}
|
||||
|
||||
static SSL*
|
||||
tls_create_object(getdns_context *context, int fd, const char* auth_name)
|
||||
tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
||||
{
|
||||
#ifdef HAVE_LIBSSL_102
|
||||
/* Create SSL instance */
|
||||
if (context->tls_ctx == NULL || auth_name == NULL)
|
||||
getdns_context *context = dnsreq->context;
|
||||
if (context->tls_ctx == NULL)
|
||||
return NULL;
|
||||
SSL* ssl = SSL_new(context->tls_ctx);
|
||||
X509_VERIFY_PARAM *param;
|
||||
|
||||
if(!ssl)
|
||||
return NULL;
|
||||
/* Connect the SSL object with a file descriptor */
|
||||
|
@ -839,16 +871,56 @@ tls_create_object(getdns_context *context, int fd, const char* auth_name)
|
|||
SSL_free(ssl);
|
||||
return NULL;
|
||||
}
|
||||
SSL_set_tlsext_host_name(ssl, auth_name);
|
||||
param = SSL_get0_param(ssl);
|
||||
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
X509_VERIFY_PARAM_set1_host(param, auth_name, 0);
|
||||
|
||||
/* NOTE: this code will fallback on a given upstream, without trying
|
||||
authentication on other upstreams first. This is non-optimal and but avoids
|
||||
multiple TLS handshakes before getting a usable connection. */
|
||||
|
||||
/* If we have a hostname, always use it */
|
||||
if (upstream->tls_auth_name[0] != '\0') {
|
||||
/*Request certificate for the auth_name*/
|
||||
SSL_set_tlsext_host_name(ssl, upstream->tls_auth_name);
|
||||
#ifdef HAVE_SSL_HN_AUTH
|
||||
/* Set up native OpenSSL hostname verification*/
|
||||
X509_VERIFY_PARAM *param;
|
||||
param = SSL_get0_param(ssl);
|
||||
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||
X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0);
|
||||
DEBUG_STUB("--- %s, HOSTNAME VERIFICATION REQUESTED \n", __FUNCTION__);
|
||||
#else
|
||||
if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) {
|
||||
/* TODO: Trigger post-handshake custom validation*/
|
||||
DEBUG_STUB("--- %s, ERROR: Authentication functionality not available\n", __FUNCTION__);
|
||||
upstream->tls_hs_state = GETDNS_HS_FAILED;
|
||||
upstream->tls_auth_failed = 1;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
/* Allow fallback to oppotunisitc if settings permit it*/
|
||||
if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME)
|
||||
SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback);
|
||||
else {
|
||||
SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_callback_with_fallback);
|
||||
SSL_CTX_set_cipher_list(context->tls_ctx, NULL);
|
||||
}
|
||||
} else {
|
||||
/* Lack of host name is OK unless only authenticated TLS is specified*/
|
||||
if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) {
|
||||
DEBUG_STUB("--- %s, ERROR: No host name provided for authentication\n", __FUNCTION__);
|
||||
upstream->tls_hs_state = GETDNS_HS_FAILED;
|
||||
upstream->tls_auth_failed = 1;
|
||||
return NULL;
|
||||
} else {
|
||||
DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__);
|
||||
upstream->tls_auth_failed = 1;
|
||||
SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_callback_with_fallback);
|
||||
SSL_CTX_set_cipher_list(context->tls_ctx, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
SSL_set_connect_state(ssl);
|
||||
(void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||
return ssl;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -905,6 +977,9 @@ tls_do_handshake(getdns_upstream *upstream)
|
|||
}
|
||||
}
|
||||
upstream->tls_hs_state = GETDNS_HS_DONE;
|
||||
r = SSL_get_verify_result(upstream->tls_obj);
|
||||
if (r == X509_V_ERR_HOSTNAME_MISMATCH)
|
||||
upstream->tls_auth_failed = 1;
|
||||
/* Reset timeout on success*/
|
||||
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
|
||||
upstream->event.read_cb = NULL;
|
||||
|
@ -1045,6 +1120,8 @@ stub_tls_write(getdns_upstream *upstream, getdns_tcp_state *tcp,
|
|||
int q = tls_connected(upstream);
|
||||
if (q != 0)
|
||||
return q;
|
||||
if (!tls_auth_status_ok(upstream, netreq))
|
||||
return STUB_TLS_SETUP_ERROR;
|
||||
|
||||
/* Do we have remaining data that we could not write before? */
|
||||
if (! tcp->write_buf) {
|
||||
|
@ -1313,9 +1390,9 @@ upstream_read_cb(void *userarg)
|
|||
if (netreq->owner == upstream->starttls_req) {
|
||||
dnsreq = netreq->owner;
|
||||
if (is_starttls_response(netreq)) {
|
||||
upstream->tls_obj = tls_create_object(dnsreq->context,
|
||||
upstream->tls_obj = tls_create_object(dnsreq,
|
||||
upstream->fd,
|
||||
upstream->tls_auth_name);
|
||||
upstream);
|
||||
if (upstream->tls_obj == NULL)
|
||||
upstream->tls_hs_state = GETDNS_HS_FAILED;
|
||||
upstream->tls_hs_state = GETDNS_HS_WRITE;
|
||||
|
@ -1451,7 +1528,8 @@ netreq_upstream_write_cb(void *userarg)
|
|||
|
||||
static int
|
||||
upstream_transport_valid(getdns_upstream *upstream,
|
||||
getdns_transport_list_t transport)
|
||||
getdns_transport_list_t transport,
|
||||
getdns_network_req *netreq)
|
||||
{
|
||||
/* Single shot UDP, uses same upstream as plain TCP. */
|
||||
if (transport == GETDNS_TRANSPORT_UDP)
|
||||
|
@ -1472,7 +1550,7 @@ upstream_transport_valid(getdns_upstream *upstream,
|
|||
/* Otherwise, transport must match, and not have failed */
|
||||
if (upstream->transport != transport)
|
||||
return 0;
|
||||
if (tls_failed(upstream))
|
||||
if (tls_failed(upstream) || !tls_auth_status_ok(upstream, netreq))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -1500,7 +1578,7 @@ upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport)
|
|||
DEBUG_STUB(" current upstream: %d of %d \n",(int)i, (int)upstreams->count);
|
||||
do {
|
||||
if (upstreams->upstreams[i].to_retry > 0 &&
|
||||
upstream_transport_valid(&upstreams->upstreams[i], transport)) {
|
||||
upstream_transport_valid(&upstreams->upstreams[i], transport, netreq)) {
|
||||
upstreams->current = i;
|
||||
DEBUG_STUB(" selected upstream: %d\n",(int)i);
|
||||
return &upstreams->upstreams[i];
|
||||
|
@ -1512,11 +1590,11 @@ upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport)
|
|||
upstream = upstreams->upstreams;
|
||||
for (i = 0; i < upstreams->count; i++)
|
||||
if (upstreams->upstreams[i].back_off < upstream->back_off &&
|
||||
upstream_transport_valid(&upstreams->upstreams[i], transport))
|
||||
upstream_transport_valid(&upstreams->upstreams[i], transport, netreq))
|
||||
upstream = &upstreams->upstreams[i];
|
||||
|
||||
/* Need to check again that the transport is valid */
|
||||
if (!upstream_transport_valid(upstream, transport)) {
|
||||
if (!upstream_transport_valid(upstream, transport, netreq)) {
|
||||
DEBUG_STUB(" ! No valid upstream available\n");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1555,7 +1633,7 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport,
|
|||
return upstream->fd;
|
||||
fd = tcp_connect(upstream, transport);
|
||||
if (fd == -1) return -1;
|
||||
upstream->tls_obj = tls_create_object(dnsreq->context, fd, upstream->tls_auth_name);
|
||||
upstream->tls_obj = tls_create_object(dnsreq, fd, upstream);
|
||||
if (upstream->tls_obj == NULL) {
|
||||
close(fd);
|
||||
return -1;
|
||||
|
@ -1598,6 +1676,7 @@ find_upstream_for_specific_transport(getdns_network_req *netreq,
|
|||
getdns_transport_list_t transport,
|
||||
int *fd)
|
||||
{
|
||||
// TODO[TLS]: Need to loop over upstreams here!!
|
||||
getdns_upstream *upstream = upstream_select(netreq, transport);
|
||||
if (!upstream)
|
||||
return NULL;
|
||||
|
|
|
@ -371,9 +371,11 @@ print_usage(FILE *out, const char *progname)
|
|||
fprintf(out, "\t-a\tPerform asynchronous resolution "
|
||||
"(default = synchronous)\n");
|
||||
fprintf(out, "\t-A\taddress lookup (<type> is ignored)\n");
|
||||
fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n");
|
||||
fprintf(out, "\t-b <bufsize>\tSet edns0 max_udp_payload size\n");
|
||||
fprintf(out, "\t-D\tSet edns0 do bit\n");
|
||||
fprintf(out, "\t-d\tclear edns0 do bit\n");
|
||||
fprintf(out, "\t-e <idle_timeout>\tSet idle timeout in miliseconds\n");
|
||||
fprintf(out, "\t-F <filename>\tread the queries from the specified file\n");
|
||||
fprintf(out, "\t-G\tgeneral lookup\n");
|
||||
fprintf(out, "\t-H\thostname lookup. (<name> must be an IP address; <type> is ignored)\n");
|
||||
|
@ -382,13 +384,15 @@ print_usage(FILE *out, const char *progname)
|
|||
fprintf(out, "\t-I\tInteractive mode (> 1 queries on same context)\n");
|
||||
fprintf(out, "\t-j\tOutput json response dict\n");
|
||||
fprintf(out, "\t-J\tPretty print json response dict\n");
|
||||
fprintf(out, "\t-n\tSet TLS authentication mode to NONE (default)\n");
|
||||
fprintf(out, "\t-m\tSet TLS authentication mode to HOSTNAME\n");
|
||||
fprintf(out, "\t-p\tPretty print response dict\n");
|
||||
fprintf(out, "\t-r\tSet recursing resolution type\n");
|
||||
fprintf(out, "\t-q\tQuiet mode - don't print response\n");
|
||||
fprintf(out, "\t-R\tPrint root trust anchors\n");
|
||||
fprintf(out, "\t-s\tSet stub resolution type (default = recursing)\n");
|
||||
fprintf(out, "\t-S\tservice lookup (<type> is ignored)\n");
|
||||
fprintf(out, "\t-t <timeout>\tSet timeout in miliseconds\n");
|
||||
fprintf(out, "\t-e <idle_timeout>\tSet idle timeout in miliseconds\n");
|
||||
fprintf(out, "\t-T\tSet transport to TCP only\n");
|
||||
fprintf(out, "\t-O\tSet transport to TCP only keep connections open\n");
|
||||
fprintf(out, "\t-L\tSet transport to TLS only keep connections open\n");
|
||||
|
@ -398,8 +402,7 @@ print_usage(FILE *out, const char *progname)
|
|||
fprintf(out, "\t-U\tSet transport to UDP only\n");
|
||||
fprintf(out, "\t-l <transports>\tSet transport list. List can contain 1 of each of the characters\n");
|
||||
fprintf(out, "\t\t\t U T L S for UDP, TCP, TLS or STARTTLS e.g 'UT' or 'LST' \n");
|
||||
fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n");
|
||||
fprintf(out, "\t-q\tQuiet mode - don't print response\n");
|
||||
|
||||
}
|
||||
|
||||
static getdns_return_t validate_chain(getdns_dict *response)
|
||||
|
@ -695,6 +698,14 @@ getdns_return_t parse_args(int argc, char **argv)
|
|||
case 'k':
|
||||
print_trust_anchors = 1;
|
||||
break;
|
||||
case 'n':
|
||||
getdns_context_set_tls_authentication(context,
|
||||
GETDNS_AUTHENTICATION_NONE);
|
||||
break;
|
||||
case 'm':
|
||||
getdns_context_set_tls_authentication(context,
|
||||
GETDNS_AUTHENTICATION_HOSTNAME);
|
||||
break;
|
||||
case 'p':
|
||||
json = 0;
|
||||
case 'q':
|
||||
|
@ -862,6 +873,9 @@ getdns_return_t do_the_call(void)
|
|||
}
|
||||
if (r == GETDNS_RETURN_GOOD && !batch_mode)
|
||||
getdns_context_run(context);
|
||||
if (r != GETDNS_RETURN_GOOD)
|
||||
fprintf(stderr, "An error occurred: %d '%s'\n", r,
|
||||
getdns_get_errorstr_by_id(r));
|
||||
} else {
|
||||
switch (calltype) {
|
||||
case GENERAL:
|
||||
|
|
|
@ -55,7 +55,7 @@ usage () {
|
|||
echo "can be specified via the command line option."
|
||||
echo
|
||||
echo "usage: test_transport.sh"
|
||||
ehco " -p path to getdns_query binary"
|
||||
echo " -p path to getdns_query binary"
|
||||
echo " -s server configured for only TCP and UDP"
|
||||
echo " -t server configured for TLS, STARTTLS, TCP and UDP"
|
||||
echo " (This must include the hostname e.g. 185.49.141.38~www.dnssec-name-and-shame.com)"
|
||||
|
@ -77,20 +77,22 @@ echo $TLS_SERVER_IP_NO_NAME
|
|||
GOOD_QUERIES=(
|
||||
"-s -A -q getdnsapi.net -l U @${SERVER_IP} "
|
||||
"-s -A -q getdnsapi.net -l T @${SERVER_IP} "
|
||||
"-s -A -q getdnsapi.net -l L @${TLS_SERVER_IP}"
|
||||
"-s -A -q getdnsapi.net -l S @${TLS_SERVER_IP}")
|
||||
"-s -A -q getdnsapi.net -l L @${TLS_SERVER_IP_NO_NAME}"
|
||||
"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP}")
|
||||
#"-s -A -q getdnsapi.net -l S @${TLS_SERVER_IP_NO_NAME}")
|
||||
|
||||
GOOD_FALLBACK_QUERIES=(
|
||||
"-s -A -q getdnsapi.net -l LT @${SERVER_IP}"
|
||||
"-s -A -q getdnsapi.net -l LT @${SERVER_IP}"
|
||||
"-s -A -q getdnsapi.net -l LT @${TLS_SERVER_IP_NO_NAME}"
|
||||
"-s -A -q getdnsapi.net -l L @${SERVER_IP} @${TLS_SERVER_IP}"
|
||||
"-s -A -q getdnsapi.net -l LT -m @${TLS_SERVER_IP_NO_NAME}"
|
||||
"-s -A -q getdnsapi.net -l L @${SERVER_IP} @${TLS_SERVER_IP_NO_NAME}"
|
||||
"-s -G -q DNSKEY getdnsapi.net -l UT @${SERVER_IP} -b 512 -D")
|
||||
|
||||
NOT_AVAILABLE_QUERIES=(
|
||||
"-s -A -q getdnsapi.net -l L @${SERVER_IP} "
|
||||
"-s -A -q getdnsapi.net -l S @${SERVER_IP} "
|
||||
"-s -A -q getdnsapi.net -l L @${TLS_SERVER_IP_NO_NAME} "
|
||||
#"-s -A -q getdnsapi.net -l S @${SERVER_IP} "
|
||||
"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} "
|
||||
"-s -G -q DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D")
|
||||
|
||||
echo "Starting transport test"
|
||||
|
|
|
@ -213,8 +213,9 @@ typedef struct getdns_network_req
|
|||
struct getdns_upstream *upstream;
|
||||
int fd;
|
||||
getdns_transport_list_t transports[GETDNS_TRANSPORTS_MAX];
|
||||
size_t transport_count;
|
||||
size_t transport_current;
|
||||
size_t transport_count;
|
||||
size_t transport_current;
|
||||
getdns_tls_authentication_t tls_auth_min;
|
||||
getdns_eventloop_event event;
|
||||
getdns_tcp_state tcp;
|
||||
uint16_t query_id;
|
||||
|
|
Loading…
Reference in New Issue