diff --git a/ChangeLog b/ChangeLog index 94c09909..74e977dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,9 @@ * 2017-12-??: Version 1.3.0 - * Specify available cipher suites for authenticated TLS upstreams - with getdns_context_set_tls_ciphers_list() + * Specify default available cipher suites for authenticated TLS + upstreams with getdns_context_set_tls_ciphers_list() + An upstream specific available cipher suite may also be given + with the tls_cipher_list setting in the upstream dict with + getdns_context_set_upstream_recursive_servers() * PR #366: Add support for TLS 1.3 and Chacha20-Poly1305 Thanks Pascal Ernster * Bugfix #356: Do Zero configuration DNSSEC meta queries over on the diff --git a/src/context.c b/src/context.c index 973f577b..b50dff1a 100644 --- a/src/context.c +++ b/src/context.c @@ -165,6 +165,17 @@ static void set_ub_dnssec_allowed_skew(struct getdns_context*, uint32_t); /* Stuff to make it compile pedantically */ #define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code; +static char * +_getdns_strdup2(const struct mem_funcs *mfs, const getdns_bindata *s) +{ + char *r; + if (!s || !(r = GETDNS_XMALLOC(*mfs, char, s->size + 1))) + return NULL; + else { + r[s->size] = '\0'; + return memcpy(r, s, s->size); + } +} #ifdef USE_WINSOCK /* For windows, the CA trust store is not read by openssl. @@ -723,6 +734,8 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams) pin = nextpin; } upstream->tls_pubkey_pinset = NULL; + if (upstream->tls_cipher_list) + GETDNS_FREE(upstreams->mf, upstream->tls_cipher_list); } GETDNS_FREE(upstreams->mf, upstreams); } @@ -1006,6 +1019,7 @@ upstream_init(getdns_upstream *upstream, upstream->fd = -1; upstream->tls_obj = NULL; upstream->tls_session = NULL; + upstream->tls_cipher_list = NULL; upstream->transport = GETDNS_TRANSPORT_TCP; upstream->tls_hs_state = GETDNS_HS_NONE; upstream->tls_auth_name[0] = '\0'; @@ -2977,16 +2991,19 @@ 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) { + if (dict && getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) { getdns_list *pubkey_pinset = NULL; - if (dict && (r = getdns_dict_get_bindata( + getdns_bindata *tls_cipher_list = NULL; + + if ((r = getdns_dict_get_bindata( dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) { if (tls_auth_name->size >= sizeof(upstream->tls_auth_name)) { - /* tls_auth_name's are just - * domain names and should - * thus not be larger than 256 - * bytes. + /* tls_auth_name's are + * domain names in presentation + * format and, taking escaping + * into account, should not + * be larger than 1024 bytes. */ goto invalid_parameter; } @@ -2996,7 +3013,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, upstream->tls_auth_name [tls_auth_name->size] = '\0'; } - if (dict && (r = getdns_dict_get_list(dict, "tls_pubkey_pinset", + if ((r = getdns_dict_get_list(dict, "tls_pubkey_pinset", &pubkey_pinset)) == GETDNS_RETURN_GOOD) { /* TODO: what if the user supplies tls_pubkey_pinset with * something other than a list? */ @@ -3006,6 +3023,12 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, if (r != GETDNS_RETURN_GOOD) goto invalid_parameter; } + (void) getdns_dict_get_bindata( + dict, "tls_cipher_list", &tls_cipher_list); + upstream->tls_cipher_list = tls_cipher_list + ? _getdns_strdup2(&upstreams->mf + , tls_cipher_list) + : NULL; } if ((upstream->tsig_alg = tsig_alg)) { if (tsig_name) { @@ -3631,7 +3654,7 @@ _getdns_context_prepare_for_resolution(getdns_context *context) return r; } /* _getdns_context_prepare_for_resolution */ -char * +static char * _getdns_strdup(const struct mem_funcs *mfs, const char *s) { size_t sz; @@ -4483,6 +4506,11 @@ getdns_context_get_upstream_recursive_servers(getdns_context *context, break; } } + if (upstream->tls_cipher_list) { + (void) getdns_dict_util_set_string( + d, "tls_cipher_list", + upstream->tls_cipher_list); + } } } if (!r) diff --git a/src/context.h b/src/context.h index beab21ac..86f40b03 100644 --- a/src/context.h +++ b/src/context.h @@ -205,6 +205,7 @@ typedef struct getdns_upstream { getdns_tls_hs_state_t tls_hs_state; getdns_auth_state_t tls_auth_state; unsigned tls_fallback_ok : 1; + char *tls_cipher_list; /* Auth credentials*/ char tls_auth_name[256]; sha256_pin_t *tls_pubkey_pinset; @@ -528,8 +529,6 @@ void _getdns_context_cancel_request(getdns_dns_req *dnsreq); */ void _getdns_context_request_timed_out(getdns_dns_req *dnsreq); -char *_getdns_strdup(const struct mem_funcs *mfs, const char *str); - struct getdns_bindata *_getdns_bindata_copy( struct mem_funcs *mfs, size_t size, const uint8_t *data); diff --git a/src/getdns/getdns.h.in b/src/getdns/getdns.h.in index 4732a4a3..788f0d94 100644 --- a/src/getdns/getdns.h.in +++ b/src/getdns/getdns.h.in @@ -1687,6 +1687,8 @@ getdns_context_set_dnssec_allowed_skew(getdns_context *context, * - `value` A SHA256 hash of the `SubjectPublicKeyInfo` * of the upstream, which will be used to authenticate * it. + * - `tls_cipher_list` (a bindata) that is the string + * of available ciphers specific for this upstream. * @return GETDNS_RETURN_GOOD when successful. * @return GETDNS_RETURN_INVALID_PARAMETER when `context` or `upstream_list` was `NULL` * @return GETDNS_RETURN_CONTEXT_UPDATE_FAIL when there were problems parsing diff --git a/src/stub.c b/src/stub.c index d8da9a9c..07f22fcd 100644 --- a/src/stub.c +++ b/src/stub.c @@ -986,9 +986,12 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) SSL_set_cipher_list(ssl, "DEFAULT"); DEBUG_STUB("%s %-35s: WARNING: Using Oppotunistic TLS (fallback allowed)!\n", STUB_DEBUG_SETUP_TLS, __FUNC__); - } else + } else { + if (upstream->tls_cipher_list) + SSL_set_cipher_list(ssl, upstream->tls_cipher_list); DEBUG_STUB("%s %-35s: Using Strict TLS \n", STUB_DEBUG_SETUP_TLS, __FUNC__); + } SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback); SSL_set_connect_state(ssl);