From 28ffb2fdf61956973aa0a8b3a82691b1f5712d85 Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Wed, 30 Sep 2015 14:03:15 +0100 Subject: [PATCH] Add ls_authentication to API --- src/const-info.c | 2 ++ src/context.c | 60 ++++++++++++++++++++++++++++------------- src/context.h | 5 ++-- src/getdns/getdns.h.in | 26 +++++++++++++++++- src/libgetdns.symbols | 1 + src/request-internal.c | 3 +-- src/stub.c | 19 ++++++++----- src/test/getdns_query.c | 21 ++++++++++++--- src/types-internal.h | 3 +-- 9 files changed, 103 insertions(+), 37 deletions(-) diff --git a/src/const-info.c b/src/const-info.c index 900989de..7555c156 100644 --- a/src/const-info.c +++ b/src/const-info.c @@ -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) diff --git a/src/context.c b/src/context.c index b5aca374..0d881be2 100644 --- a/src/context.c +++ b/src/context.c @@ -900,8 +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_req = 1; - result->tls_auth_fallback_ok = 1; + result->tls_auth = GETDNS_AUTHENTICATION_HOSTNAME; + result->tls_auth_min = GETDNS_AUTHENTICATION_HOSTNAME; result->limit_outstanding_queries = 0; result->return_dnssec_status = GETDNS_EXTENSION_FALSE; @@ -1262,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) @@ -1274,7 +1273,7 @@ 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); + dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_TRANSPORT); return GETDNS_RETURN_GOOD; } @@ -1423,6 +1422,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 */ @@ -2178,23 +2197,18 @@ _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) { + 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()); if(context->tls_ctx == NULL) return GETDNS_RETURN_BAD_CONTEXT; - /* Be strict and only use the cipher suites recommended in RFC7525 */ - 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 ((tls_only_is_in_transports_list(context) == 1) && context->tls_auth_req) - context->tls_auth_fallback_ok = 0; - /* TODO: If no auth data provided for any upstream, fail here */ - else - context->tls_auth_fallback_ok = 1; + // /* Be strict and only use the cipher suites recommended in RFC7525 */ + // 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; /* By default cert chain will be verified, but note that per connection management of the result and hostname verification is done.*/ SSL_CTX_set_verify(context->tls_ctx, SSL_VERIFY_PEER, _getdns_tls_verify_callback); @@ -2206,9 +2220,19 @@ _getdns_context_prepare_for_resolution(struct getdns_context *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) { + fprintf(stdout, "Setting auth min to HOSTNAME\n"); + 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; + fprintf(stdout, "Setting auth min to NONE\n"); } } + /* 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. */ diff --git a/src/context.h b/src/context.h index 5c16a6ff..8a205e4e 100644 --- a/src/context.h +++ b/src/context.h @@ -146,9 +146,8 @@ struct getdns_context { getdns_upstreams *upstreams; uint16_t limit_outstanding_queries; uint32_t dnssec_allowed_skew; - /*Make this a list*/ - size_t tls_auth_req; - size_t tls_auth_fallback_ok; /*Redundant but convinient*/ + 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; diff --git a/src/getdns/getdns.h.in b/src/getdns/getdns.h.in index 3f24250e..d75fb00a 100644 --- a/src/getdns/getdns.h.in +++ b/src/getdns/getdns.h.in @@ -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); diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index 3eb60c4a..c0241c31 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -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 diff --git a/src/request-internal.c b/src/request-internal.c index 42dce648..30156724 100644 --- a/src/request-internal.c +++ b/src/request-internal.c @@ -104,8 +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_req = owner->context->tls_auth_req; - net_req->tls_auth_fallback_ok = owner->context->tls_auth_fallback_ok; + 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; diff --git a/src/stub.c b/src/stub.c index a3c94d83..996cdc88 100644 --- a/src/stub.c +++ b/src/stub.c @@ -824,9 +824,9 @@ tls_failed(getdns_upstream *upstream) static int tls_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) { - return (netreq->tls_auth_req && - !netreq->tls_auth_fallback_ok && - upstream->tls_auth_failed) ? 0 : 1; + DEBUG_STUB("--- %s %d %d\n", __FUNCTION__, (int)netreq->tls_auth_min, (int)upstream->tls_auth_failed); + return (netreq->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME && + upstream->tls_auth_failed) ? 0 : 1; } int @@ -879,13 +879,15 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) /* Lack of host name is OK unless only authenticated TLS is specified*/ if (upstream->tls_auth_name[0] == '\0') { - if (!dnsreq->netreqs[0]->tls_auth_fallback_ok) { + 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; + /* TODO: Should we always enforce validation of the cert at least??*/ SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); } } else { @@ -900,15 +902,15 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0); #else /* TODO: Trigger post-handshake custom validation*/ - if (!dnsreq->netreqs[0]->tls_auth_fallback_ok) { + if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) { 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 from authenticated TLS if settings permit it (use NONE here?)*/ - if (dnsreq->netreqs[0]->tls_auth_fallback_ok) + /* Allow fallback from authenticated TLS if settings permit it*/ + if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_NONE) SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_callback_with_fallback); } @@ -1118,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) { @@ -1672,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; diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 94942e94..8c1b2e5e 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -193,8 +193,10 @@ void my_eventloop_run_once(getdns_eventloop *loop, int blocking) tv.tv_sec = 0; tv.tv_usec = 0; } else { - tv.tv_sec = (timeout - now) / 1000000; + //tv.tv_sec = (timeout - now) / 1000000; + tv.tv_sec = 21474836; tv.tv_usec = (timeout - now) % 1000000; + //fprintf(stdout, "Using BIG tv: %" PRIu64 " %" PRIu64 ", %lu %d \n", timeout, now, tv.tv_sec, tv.tv_usec); } if (select(max_fd + 1, &readfds, &writefds, NULL, &tv) < 0) { perror("select() failed"); @@ -371,9 +373,11 @@ print_usage(FILE *out, const char *progname) fprintf(out, "\t-a\tPerform asynchronous resolution " "(default = synchronous)\n"); fprintf(out, "\t-A\taddress lookup ( is ignored)\n"); + fprintf(out, "\t-B\tBatch mode. Schedule all messages before processing responses.\n"); fprintf(out, "\t-b \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 \tSet idle timeout in miliseconds\n"); fprintf(out, "\t-F \tread the queries from the specified file\n"); fprintf(out, "\t-G\tgeneral lookup\n"); fprintf(out, "\t-H\thostname lookup. ( must be an IP address; is ignored)\n"); @@ -382,13 +386,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 is to verify hostname)\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 ( is ignored)\n"); fprintf(out, "\t-t \tSet timeout in miliseconds\n"); - fprintf(out, "\t-e \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 +404,7 @@ print_usage(FILE *out, const char *progname) fprintf(out, "\t-U\tSet transport to UDP only\n"); fprintf(out, "\t-l \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 +700,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': diff --git a/src/types-internal.h b/src/types-internal.h index 9f0458eb..08b3acc2 100644 --- a/src/types-internal.h +++ b/src/types-internal.h @@ -198,8 +198,7 @@ typedef struct getdns_network_req getdns_transport_list_t transports[GETDNS_TRANSPORTS_MAX]; size_t transport_count; size_t transport_current; - size_t tls_auth_req; - size_t tls_auth_fallback_ok; + getdns_tls_authentication_t tls_auth_min; getdns_eventloop_event event; getdns_tcp_state tcp; uint16_t query_id;