mirror of https://github.com/getdnsapi/getdns.git
Merge pull request #112 from saradickinson/features/tls_auth
Features/tls auth
This commit is contained in:
commit
d436165a88
7
INSTALL
7
INSTALL
|
@ -254,6 +254,13 @@ not `/usr/local'. It is recommended to use the following options:
|
|||
|
||||
./configure --prefix=/boot/common
|
||||
|
||||
On Mac OSX getdns will not build against the version of OpenSSL shipped with
|
||||
OSX. If you link against a self-complied version of OpenSSL then manual
|
||||
configuration of certificates into the default OpenSSL directory
|
||||
/usr/local/etc/openssl/certs is currently required for TLS authentication to work.
|
||||
However if linking against the version of OpenSSL installed via Homebrew TLS
|
||||
authentication will work out of the box.
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
|
|
|
@ -89,6 +89,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
|
||||
* [libexpat](http://expat.sourceforge.net/) for libunbound.
|
||||
* [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)
|
||||
* 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
|
||||
|
@ -149,8 +150,6 @@ There are a few known issues which we have summarized below - the most recent
|
|||
and helpful list is being maintained in the git issues list in the repository.
|
||||
Other known issues are being managed in the git repository issue list.
|
||||
|
||||
* (#113) Changing the resolution type between stub and recursive after a query has been issued with a context will not work - the previous resolution type will continue to be used. If you want to change the resolution type you will need to create a new context and set the resolution type for that context.
|
||||
|
||||
* When doing a synchronous lookup with a context that has outstanding asynchronous lookups, the callbacks for the asynchronous lookups might get called as a side effect of the synchronous lookup.
|
||||
|
||||
|
||||
|
@ -214,6 +213,9 @@ build the packages, this is simplythe one we chose to use.
|
|||
|
||||
create dmg
|
||||
|
||||
A self-compiled version of OpenSSL or the version installed via Homebrew is required.
|
||||
Note: If using a self-compiled version manual configuration of certificates into /usr/local/etc/openssl/certs is required for TLS authentication to work.
|
||||
|
||||
#### Homebrew
|
||||
|
||||
If you're using [Homebrew](http://brew.sh/), you may run `brew install getdns`. By default, this will only build the core library without any 3rd party event loop support.
|
||||
|
@ -222,7 +224,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 lib installed by Homebrew is linked against.
|
||||
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.
|
||||
|
||||
Contributors
|
||||
============
|
||||
|
|
|
@ -105,8 +105,9 @@ 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])
|
||||
AC_CHECK_LIB(ssl, TLSv1_2_client_method,AC_DEFINE([HAVE_LIBTLS1_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 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 Check for SSL, where SSL is mandatory
|
||||
|
|
|
@ -2209,7 +2209,9 @@ getdns_context_set_dns_transport_list(
|
|||
<p class=cont>The <code>transports</code> array contains an ordered list of transports that will be used for DNS lookups.
|
||||
If only one transport value is specified it will be the only transport used.
|
||||
Should it not be available basic resolution will fail.
|
||||
Fallback transport options are specified by including multiple values in the list.
|
||||
Fallback transport options are specified by including multiple values in the list. Currently the TLS and STARTTLS options
|
||||
perform Strict TLS which requires a hostname to be
|
||||
specified so that authentication can be performed. This hostname can be specified in the tls_auth_name parameter for an upstream.
|
||||
The values are <span class=default>
|
||||
<code>GETDNS_TRANSPORT_UDP</code></span>,
|
||||
<code>GETDNS_TRANSPORT_TCP</code>,
|
||||
|
|
|
@ -578,6 +578,27 @@ priv_getdns_upstream_shutdown(getdns_upstream *upstream)
|
|||
close(fd);
|
||||
}
|
||||
|
||||
static int
|
||||
tls_is_in_transports_list(getdns_context *context) {
|
||||
for (int i=0; i< context->dns_transport_count;i++) {
|
||||
if (context->dns_transports[i] == GETDNS_TRANSPORT_TLS ||
|
||||
context->dns_transports[i] == GETDNS_TRANSPORT_STARTTLS)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tls_only_is_in_transports_list(getdns_context *context) {
|
||||
if (context->dns_transport_count != 1)
|
||||
return 0;
|
||||
if (context->dns_transports[0] == GETDNS_TRANSPORT_TLS ||
|
||||
context->dns_transports[0] == GETDNS_TRANSPORT_STARTTLS)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
net_req_query_id_cmp(const void *id1, const void *id2)
|
||||
{
|
||||
|
@ -605,6 +626,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_name[0] = '\0';
|
||||
upstream->tcp.write_error = 0;
|
||||
upstream->loop = NULL;
|
||||
(void) getdns_eventloop_event_init(
|
||||
|
@ -1216,14 +1238,20 @@ getdns_set_base_dns_transports(
|
|||
if (!context || transport_count == 0 || transports == NULL)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
/* Check for valid transports and that they are used only once*/
|
||||
int u=0,t=0,l=0,s=0;
|
||||
for(i=0; i<transport_count; i++)
|
||||
{
|
||||
if( transports[i] != GETDNS_TRANSPORT_UDP
|
||||
&& transports[i] != GETDNS_TRANSPORT_TCP
|
||||
&& transports[i] != GETDNS_TRANSPORT_TLS
|
||||
&& transports[i] != GETDNS_TRANSPORT_STARTTLS)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
switch (transports[i]) {
|
||||
case GETDNS_TRANSPORT_UDP: u++; break;
|
||||
case GETDNS_TRANSPORT_TCP: t++; break;
|
||||
case GETDNS_TRANSPORT_TLS: l++; break;
|
||||
case GETDNS_TRANSPORT_STARTTLS: s++; break;
|
||||
default: return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
if ( u>1 || t>1 || l>1 || s>1)
|
||||
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||
|
||||
if (!(new_transports = GETDNS_XMALLOC(context->my_mf,
|
||||
getdns_transport_list_t, transport_count)))
|
||||
|
@ -1662,6 +1690,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
getdns_dict *dict;
|
||||
getdns_bindata *address_type;
|
||||
getdns_bindata *address_data;
|
||||
getdns_bindata *tls_auth_name;
|
||||
struct sockaddr_storage addr;
|
||||
|
||||
getdns_bindata *scope_id;
|
||||
|
@ -1735,6 +1764,17 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
|||
upstream->addr.ss_family = addr.ss_family;
|
||||
upstream_init(upstream, upstreams, ai);
|
||||
upstream->transport = getdns_upstream_transports[j];
|
||||
if (getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS ||
|
||||
getdns_upstream_transports[j] == GETDNS_TRANSPORT_STARTTLS) {
|
||||
if ((r = getdns_dict_get_bindata(
|
||||
dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) {
|
||||
/*TODO: VALIDATE THIS STRING!*/
|
||||
memcpy(upstream->tls_auth_name,
|
||||
(char *)tls_auth_name->data,
|
||||
tls_auth_name->size);
|
||||
upstream->tls_auth_name[tls_auth_name->size] = '\0';
|
||||
}
|
||||
}
|
||||
upstreams->count++;
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
|
@ -2122,23 +2162,24 @@ 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) {
|
||||
/*TODO[TLS]: Check if TLS is in the list of transports.*/
|
||||
if (context->tls_ctx == NULL) {
|
||||
#ifdef HAVE_LIBTLS1_2
|
||||
if (tls_is_in_transports_list(context) == 1 &&
|
||||
context->tls_ctx == NULL) {
|
||||
#ifdef HAVE_LIBSSL_102
|
||||
/* 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);
|
||||
if (!SSL_CTX_set_default_verify_paths(context->tls_ctx))
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
}
|
||||
}
|
||||
/* 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. */
|
||||
* 53 so it is blocked here. So is 'STARTTLS only' at the moment. */
|
||||
if (context->resolution_type == GETDNS_RESOLUTION_RECURSING &&
|
||||
context->dns_transport_count == 1 &&
|
||||
(context->dns_transports[0] == GETDNS_TRANSPORT_TLS ||
|
||||
context->dns_transports[0] == GETDNS_TRANSPORT_STARTTLS))
|
||||
tls_only_is_in_transports_list(context) == 1)
|
||||
return GETDNS_RETURN_BAD_CONTEXT;
|
||||
|
||||
if (context->resolution_type_set == context->resolution_type)
|
||||
|
|
|
@ -101,6 +101,7 @@ typedef struct getdns_upstream {
|
|||
getdns_eventloop_event event;
|
||||
getdns_eventloop *loop;
|
||||
getdns_tcp_state tcp;
|
||||
char tls_auth_name[256];
|
||||
|
||||
/* Pipelining of TCP network requests */
|
||||
getdns_network_req *write_queue;
|
||||
|
|
21
src/stub.c
21
src/stub.c
|
@ -32,6 +32,7 @@
|
|||
*/
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include "config.h"
|
||||
#include <fcntl.h>
|
||||
#include "stub.h"
|
||||
|
@ -822,12 +823,15 @@ tls_failed(getdns_upstream *upstream)
|
|||
}
|
||||
|
||||
static SSL*
|
||||
tls_create_object(getdns_context *context, int fd)
|
||||
tls_create_object(getdns_context *context, int fd, const char* auth_name)
|
||||
{
|
||||
#ifdef HAVE_LIBSSL_102
|
||||
/* Create SSL instance */
|
||||
if (context->tls_ctx == NULL)
|
||||
if (context->tls_ctx == NULL || auth_name == 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 */
|
||||
|
@ -835,9 +839,16 @@ tls_create_object(getdns_context *context, int fd)
|
|||
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);
|
||||
SSL_set_connect_state(ssl);
|
||||
(void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||
return ssl;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -889,6 +900,7 @@ tls_do_handshake(getdns_upstream *upstream)
|
|||
upstream->tls_hs_state = GETDNS_HS_WRITE;
|
||||
return STUB_TCP_AGAIN;
|
||||
default:
|
||||
DEBUG_STUB("--- %s %s %d\n", __FUNCTION__, "Handshake failed: ", want);
|
||||
return tls_cleanup(upstream);
|
||||
}
|
||||
}
|
||||
|
@ -1302,7 +1314,8 @@ upstream_read_cb(void *userarg)
|
|||
dnsreq = netreq->owner;
|
||||
if (is_starttls_response(netreq)) {
|
||||
upstream->tls_obj = tls_create_object(dnsreq->context,
|
||||
upstream->fd);
|
||||
upstream->fd,
|
||||
upstream->tls_auth_name);
|
||||
if (upstream->tls_obj == NULL)
|
||||
upstream->tls_hs_state = GETDNS_HS_FAILED;
|
||||
upstream->tls_hs_state = GETDNS_HS_WRITE;
|
||||
|
@ -1542,7 +1555,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_obj = tls_create_object(dnsreq->context, fd, upstream->tls_auth_name);
|
||||
if (upstream->tls_obj == NULL) {
|
||||
close(fd);
|
||||
return -1;
|
||||
|
|
|
@ -55,6 +55,7 @@ ipaddr_dict(getdns_context *context, char *ipstr)
|
|||
char *s = strchr(ipstr, '%'), *scope_id_str = "";
|
||||
char *p = strchr(ipstr, '@'), *portstr = "";
|
||||
char *t = strchr(ipstr, '#'), *tls_portstr = "";
|
||||
char *n = strchr(ipstr, '~'), *tls_namestr = "";
|
||||
uint8_t buf[sizeof(struct in6_addr)];
|
||||
getdns_bindata addr;
|
||||
|
||||
|
@ -73,6 +74,10 @@ ipaddr_dict(getdns_context *context, char *ipstr)
|
|||
*t = 0;
|
||||
tls_portstr = t + 1;
|
||||
}
|
||||
if (n) {
|
||||
*n = 0;
|
||||
tls_namestr = n + 1;
|
||||
}
|
||||
if (strchr(ipstr, ':')) {
|
||||
getdns_dict_util_set_string(r, "address_type", "IPv6");
|
||||
addr.size = 16;
|
||||
|
@ -93,6 +98,9 @@ ipaddr_dict(getdns_context *context, char *ipstr)
|
|||
getdns_dict_set_int(r, "port", (int32_t)atoi(portstr));
|
||||
if (*tls_portstr)
|
||||
getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr));
|
||||
if (*tls_namestr) {
|
||||
getdns_dict_util_set_string(r, "tls_auth_name", tls_namestr);
|
||||
}
|
||||
if (*scope_id_str)
|
||||
getdns_dict_util_set_string(r, "scope_id", scope_id_str);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
SERVER_IP="8.8.8.8"
|
||||
TLS_SERVER_IP="185.49.141.38"
|
||||
TLS_SERVER_IP="185.49.141.38~www.dnssec-name-and-shame.com"
|
||||
GOOD_RESULT_SYNC="Status was: At least one response was returned"
|
||||
GOOD_RESULT_ASYNC="successfull"
|
||||
BAD_RESULT_SYNC="1 'Generic error'"
|
||||
|
@ -58,6 +58,7 @@ usage () {
|
|||
ehco " -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)"
|
||||
}
|
||||
|
||||
while getopts ":p:s:t:dh" opt; do
|
||||
|
@ -70,6 +71,9 @@ while getopts ":p:s:t:dh" opt; do
|
|||
esac
|
||||
done
|
||||
|
||||
TLS_SERVER_IP_NO_NAME=`echo ${TLS_SERVER_IP%~*}`
|
||||
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} "
|
||||
|
@ -78,13 +82,15 @@ GOOD_QUERIES=(
|
|||
|
||||
GOOD_FALLBACK_QUERIES=(
|
||||
"-s -A -q getdnsapi.net -l LT @${SERVER_IP}"
|
||||
"-s -A -q getdnsapi.net -l LU @${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 -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 -G -q DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D")
|
||||
|
||||
echo "Starting transport test"
|
||||
|
|
Loading…
Reference in New Issue