From 4047bd09dae097405d34cc59cf5a7e5ff7faa75a Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Fri, 18 Dec 2015 09:57:23 -0500 Subject: [PATCH 01/17] define _DEFAULT_SOURCE as well as _BSD_SOURCE for glibc version 2.20 and up in recent versions of feature_test_macros(7), it says of _BSD_SOURCE: Since glibc 2.20, this macro is deprecated. It now has the same effect as defining _DEFAULT_SOURCE, but generates a compile-time warning (unless _DEFAULT_SOURCE is also defined). Use _DEFAULT_SOURCE instead. To allow code that requires _BSD_SOURCE in glibc 2.19 and earlier and _DEFAULT_SOURCE in glibc 2.20 and later to compile without warnings, define both _BSD_SOURCE and _DEFAULT_SOURCE. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4b0ed882..dcae8b46 100644 --- a/configure.ac +++ b/configure.ac @@ -98,7 +98,7 @@ AX_CHECK_COMPILE_FLAG([-xc99],[CFLAGS="$CFLAGS -xc99"],[],[]) AX_CHECK_COMPILE_FLAG([-Wall],[CFLAGS="$CFLAGS -Wall"],[],[]) case "$host_os" in - linux* ) CFLAGS="$CFLAGS -D_BSD_SOURCE" + linux* ) CFLAGS="$CFLAGS -D_BSD_SOURCE -D_DEFAULT_SOURCE" ;; solaris* ) CFLAGS="$CFLAGS -D__EXTENSIONS__" # for strdup() from ;; From 91f04ecd5edfe0a7a2f9ddf0bc216f149b75df88 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 20 Dec 2015 12:58:50 -0500 Subject: [PATCH 02/17] add getdns_pubkey_pin_create_from_string() --- src/Makefile.in | 7 +- src/getdns/getdns_extra.h.in | 37 +++++++++ src/libgetdns.symbols | 1 + src/pubkey-pinning.c | 140 +++++++++++++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 src/pubkey-pinning.c diff --git a/src/Makefile.in b/src/Makefile.in index fc323242..f1e23c8a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -64,8 +64,8 @@ EXTENSION_LIBUV_LDFLAGS=@EXTENSION_LIBUV_LDFLAGS@ C99COMPATFLAGS=@C99COMPATFLAGS@ GETDNS_OBJ=const-info.lo convert.lo dict.lo dnssec.lo general.lo \ - list.lo request-internal.lo rr-dict.lo rr-iter.lo stub.lo sync.lo \ - util-internal.lo + list.lo request-internal.lo pubkey-pinning.lo rr-dict.lo \ + rr-iter.lo stub.lo sync.lo util-internal.lo GLDNS_OBJ=keyraw.lo gbuffer.lo wire2str.lo parse.lo parseutil.lo rrdef.lo \ str2wire.lo @@ -326,6 +326,9 @@ libevent.lo libevent.o: $(srcdir)/extension/libevent.c config.h $(srcdir)/types- libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c config.h $(srcdir)/debug.h config.h \ $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h \ $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h +<<<<<<< HEAD libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/debug.h config.h $(srcdir)/types-internal.h \ getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ $(srcdir)/getdns/getdns_ext_libuv.h getdns/getdns_extra.h +pubkey-pinning.lo pubkey-pinning.o: $(srcdir)/pubkey-pinning.c \ + config.h getdns/getdns.h diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index a33e6f4a..12161e10 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -342,6 +342,41 @@ getdns_context_get_update_callback(getdns_context *context, void **userarg, */ const char *getdns_get_errorstr_by_id(uint16_t err); + + +/** + * Public Key Pinning functionality: + * + * a public key pinset is a list of dicts. each dict should have a + * "digest" and a "value". + * + * "digest": a string indicating the type of digest. at the moment, we + * only support a "digest" of "sha256". + * + * "value": a binary representation of the digest provided. + * + * given a such a pinset, we should be able to validate a chain + * properly according to section 2.6 of RFC 7469. + */ + +/** + * convert an HPKP-style pin description to an appropriate getdns data + * structure. An example string is: (with the quotes, without any + * leading or trailing whitespace): + * + * pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" + * + * It is the caller's responsibility to call getdns_dict_destroy() on + * the dict returned when it is no longer needed. + * + * @param context a context to use to create the dict, or NULL to create + * it generically + * @param str the pinning string to parse + * @return a dict created from ctx, or NULL if the string did not match. + */ +getdns_dict* getdns_pubkey_pin_create_from_string( + getdns_context* context, + const char* str); /* WARNING! Function getdns_strerror is not in the API specification and * is likely to be removed from future versions of our implementation, to be @@ -381,6 +416,8 @@ typedef enum getdns_tls_authentication_t { #define GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE_TEXT "Change related to getdns_context_set_edns_client_subnet_private" #define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE 620 #define GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE_TEXT "Change related to getdns_context_set_tls_query_padding_blocksize" +#define GETDNS_CONTEXT_CODE_PUBKEY_PINSET 621 +#define GETDNS_CONTEXT_CODE_PUBKEY_PINSET_TEXT "Change related to getdns_context_set_pubkey_pinset" getdns_return_t getdns_context_set_tls_authentication( diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index 2503c48c..9f7276cb 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -114,6 +114,7 @@ getdns_pretty_snprint_dict getdns_pretty_snprint_list getdns_print_json_dict getdns_print_json_list +getdns_pubkey_pin_create_from_string getdns_root_trust_anchor getdns_rr_dict2str getdns_rr_dict2str_buf diff --git a/src/pubkey-pinning.c b/src/pubkey-pinning.c new file mode 100644 index 00000000..b20f0817 --- /dev/null +++ b/src/pubkey-pinning.c @@ -0,0 +1,140 @@ +/** + * + * /brief functions for Public Key Pinning + * + */ + +/* + * Copyright (c) 2015, Daniel Kahn Gillmor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of the copyright holders nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * getdns Public Key Pinning + * + * a public key pinset is a list of dicts. each dict should have a + * "digest" and a "value". + * + * "digest": a string indicating the type of digest. at the moment, we + * only support a "digest" of "sha256". + * + * "value": a binary representation of the digest provided. + * + * given a such a pinset, we should be able to validate a chain + * properly according to section 2.6 of RFC 7469. + */ +#include +#include +#include +#include +#include + +/* we only support sha256 at the moment. adding support for another + digest is more complex than just adding another entry here. in + particular, you'll probably need a match for a particular cert + against all supported algorithms. better to wait on doing that + until it is a better-understood problem (i.e. wait until hpkp is + updated and follow the guidance in rfc7469bis) +*/ + +static const getdns_bindata sha256 = { + .size = sizeof("sha256") - 1, + .data = (uint8_t*)"sha256" +}; + + +#define PIN_PREFIX "pin-sha256=\"" +#define PIN_PREFIX_LENGTH (sizeof(PIN_PREFIX) - 1) +/* b64 turns every 3 octets (or fraction thereof) into 4 octets */ +#define B64_ENCODED_SHA256_LENGTH (((SHA256_DIGEST_LENGTH + 2)/3) * 4) + +/* convert an HPKP-style pin description to an appropriate getdns data + structure. An example string is: (with the quotes, without any + leading or trailing whitespace): + + pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" + + getdns_build_pin_from_string returns a dict created from ctx, or + NULL if the string did not match. If ctx is NULL, the dict is + created via getdns_dict_create(). + + It is the caller's responsibility to call getdns_dict_destroy when + it is no longer needed. + */ +getdns_dict* getdns_pubkey_pin_create_from_string( + getdns_context* context, + const char* str) +{ + BIO *bio = NULL; + int i; + uint8_t buf[SHA256_DIGEST_LENGTH]; + char inbuf[B64_ENCODED_SHA256_LENGTH + 1]; + getdns_bindata value = { .size = SHA256_DIGEST_LENGTH, .data = buf }; + getdns_dict* out = NULL; + + /* we only do sha256 right now, make sure this is well-formed */ + if (strncmp(PIN_PREFIX, str, PIN_PREFIX_LENGTH)) + return NULL; + for (i = PIN_PREFIX_LENGTH; i < PIN_PREFIX_LENGTH + B64_ENCODED_SHA256_LENGTH - 1; i++) + if (!((str[i] >= 'a' && str[i] <= 'z') || + (str[i] >= 'A' && str[i] <= 'Z') || + (str[i] >= '0' && str[i] <= '9') || + (str[i] == '+') || (str[i] == '/'))) + return NULL; + if (str[i++] != '=') + return NULL; + if (str[i++] != '"') + return NULL; + if (str[i++] != '\0') + return NULL; + + /* openssl needs a trailing newline to base64 decode */ + memcpy(inbuf, str + PIN_PREFIX_LENGTH, B64_ENCODED_SHA256_LENGTH); + inbuf[B64_ENCODED_SHA256_LENGTH] = '\n'; + + bio = BIO_push(BIO_new(BIO_f_base64()), + BIO_new_mem_buf(inbuf, sizeof(inbuf))); + if (BIO_read(bio, buf, sizeof(buf)) != sizeof(buf)) + goto fail; + + if (context) + out = getdns_dict_create_with_context(context); + else + out = getdns_dict_create(); + if (out == NULL) + goto fail; + if (getdns_dict_set_bindata(out, "digest", &sha256)) + goto fail; + if (getdns_dict_set_bindata(out, "value", &value)) + goto fail; + return out; + + fail: + BIO_free_all(bio); + getdns_dict_destroy(out); + return NULL; +} + +/* pubkey-pinning.c */ From 5e64f1262b95b2bc7e0941ac26bc6d1864fe73c6 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 20 Dec 2015 13:03:21 -0500 Subject: [PATCH 03/17] add getdns_pubkey_pinset_sanity_check() --- src/getdns/getdns_extra.h.in | 20 ++++++++++ src/libgetdns.symbols | 1 + src/pubkey-pinning.c | 75 ++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index 12161e10..dea756a6 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -378,6 +378,26 @@ getdns_dict* getdns_pubkey_pin_create_from_string( getdns_context* context, const char* str); + +/** + * Test whether a given pinset is reasonable, including: + * + * is it well-formed? + * are there at least two pins? + * are the digests used sane? + * + * @param pinset the set of public key pins to check for sanity. This + * should be a list of dicts. + * @return errorlist if not NULL, a list of human-readable strings is + * appended to errorlist. + * @return GETDNS_RETURN_GOOD if the pinset passes the sanity check. + */ +getdns_return_t getdns_pubkey_pinset_sanity_check( + const getdns_list* pinset, + getdns_list* errorlist); + + + /* WARNING! Function getdns_strerror is not in the API specification and * is likely to be removed from future versions of our implementation, to be * replaced by getdns_get_errorstr_by_id or something similar. diff --git a/src/libgetdns.symbols b/src/libgetdns.symbols index 9f7276cb..8b35ff37 100644 --- a/src/libgetdns.symbols +++ b/src/libgetdns.symbols @@ -115,6 +115,7 @@ getdns_pretty_snprint_list getdns_print_json_dict getdns_print_json_list getdns_pubkey_pin_create_from_string +getdns_pubkey_pinset_sanity_check getdns_root_trust_anchor getdns_rr_dict2str getdns_rr_dict2str_buf diff --git a/src/pubkey-pinning.c b/src/pubkey-pinning.c index b20f0817..fba25d7c 100644 --- a/src/pubkey-pinning.c +++ b/src/pubkey-pinning.c @@ -137,4 +137,79 @@ getdns_dict* getdns_pubkey_pin_create_from_string( return NULL; } + +/* Test whether a given pinset is reasonable, including: + + * is it well-formed? + * are there at least two pins? + * are the digests used sane? + + if errorlist is NULL, the sanity check just returns success or + failure. + + if errorlist is not NULL, we append human-readable strings to + report the errors. +*/ + +#define PKP_SC_ERR(e) { \ + err.size = sizeof(e); \ + err.data = (uint8_t*)e; \ + if (errorlist) \ + getdns_list_set_bindata(errorlist, \ + preverrs + errorcount, &err); \ + errorcount++; \ + } +#define PKP_SC_HARDERR(e, val) { \ + PKP_SC_ERR(e); return val; \ + } +getdns_return_t getdns_pubkey_pinset_sanity_check( + const getdns_list* pinset, + getdns_list* errorlist) +{ + size_t errorcount = 0, preverrs = 0, pins = 0, i; + getdns_bindata err; + getdns_dict * pin; + getdns_bindata * data; + + if (errorlist) + if (getdns_list_get_length(errorlist, &preverrs)) + return GETDNS_RETURN_INVALID_PARAMETER; + + if (getdns_list_get_length(pinset, &pins)) + PKP_SC_HARDERR("Can't get length of pinset", + GETDNS_RETURN_INVALID_PARAMETER); + if (pins < 2) + PKP_SC_ERR("This pinset has fewer than 2 pins"); + for (i = 0; i < pins; i++) + { + /* is it a dict? */ + if (getdns_list_get_dict(pinset, i, &pin)) { + PKP_SC_ERR("Could not retrieve a pin"); + } else { + /* does the pin have the right digest type? */ + if (getdns_dict_get_bindata(pin, "digest", &data)) { + PKP_SC_ERR("Pin has no 'digest' entry"); + } else { + if (data->size != sha256.size || + memcmp(data->data, sha256.data, sha256.size)) + PKP_SC_ERR("Pin has 'digest' other than sha256"); + } + /* if it does, is the value the right length? */ + if (getdns_dict_get_bindata(pin, "value", &data)) { + PKP_SC_ERR("Pin has no 'value' entry"); + } else { + if (data->size != SHA256_DIGEST_LENGTH) + PKP_SC_ERR("Pin has the wrong size 'value' (should be 32 octets for sha256)"); + } + + /* should we choke if it has some other key? for + * extensibility, we will not treat this as an + * error.*/ + } + } + + if (errorcount > 0) + return GETDNS_RETURN_GENERIC_ERROR; + return GETDNS_RETURN_GOOD; +} /* pubkey-pinning.c */ From 4dbe1813e408f96f22a9937ac79861f6e44f1050 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Mon, 21 Dec 2015 17:53:36 -0500 Subject: [PATCH 04/17] added simple sha256 public key pinning linked list to getdns_upstream --- src/context.c | 8 ++++++++ src/context.h | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/context.c b/src/context.c index 00c685ce..94a88f72 100644 --- a/src/context.c +++ b/src/context.c @@ -515,6 +515,7 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams) ; upstreams->count ; upstreams->count--, upstream++ ) { + sha256_pin_t *pin = upstream->tls_pubkey_pinset; if (upstream->loop && ( upstream->event.read_cb || upstream->event.write_cb || upstream->event.timeout_cb) ) { @@ -530,6 +531,12 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams) } if (upstream->fd != -1) close(upstream->fd); + while (pin) { + sha256_pin_t *nextpin = pin->next; + GETDNS_FREE(upstreams->mf, pin); + pin = nextpin; + } + upstream->tls_pubkey_pinset = NULL; } GETDNS_FREE(upstreams->mf, upstreams); } @@ -669,6 +676,7 @@ upstream_init(getdns_upstream *upstream, upstream->tls_hs_state = GETDNS_HS_NONE; upstream->tls_auth_failed = 0; upstream->tls_auth_name[0] = '\0'; + upstream->tls_pubkey_pinset = NULL; upstream->tcp.write_error = 0; upstream->loop = NULL; (void) getdns_eventloop_event_init( diff --git a/src/context.h b/src/context.h index 264cb687..729962ac 100644 --- a/src/context.h +++ b/src/context.h @@ -102,6 +102,12 @@ typedef struct getdns_tsig_info { const getdns_tsig_info *_getdns_get_tsig_info(getdns_tsig_algo tsig_alg); +/* for doing public key pinning of TLS-capable upstreams: */ +typedef struct sha256_pin { + char pin[SHA256_DIGEST_LENGTH]; + struct sha256_pin *next; +} sha256_pin_t; + typedef struct getdns_upstream { /* backpointer to containing upstreams structure */ struct getdns_upstreams *upstreams; @@ -126,6 +132,7 @@ typedef struct getdns_upstream { getdns_tcp_state tcp; char tls_auth_name[256]; size_t tls_auth_failed; + sha256_pin_t *tls_pubkey_pinset; /* Pipelining of TCP network requests */ getdns_network_req *write_queue; From b305f073fe85421aa434e37993f1344e0466646d Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Mon, 21 Dec 2015 17:54:43 -0500 Subject: [PATCH 05/17] add functions to translate between getdns_list and sha256_pin linked list --- src/pubkey-pinning.c | 97 ++++++++++++++++++++++++++++++++++++++++++++ src/pubkey-pinning.h | 53 ++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 src/pubkey-pinning.h diff --git a/src/pubkey-pinning.c b/src/pubkey-pinning.c index fba25d7c..96d37fe1 100644 --- a/src/pubkey-pinning.c +++ b/src/pubkey-pinning.c @@ -50,6 +50,7 @@ #include #include #include +#include "context.h" /* we only support sha256 at the moment. adding support for another digest is more complex than just adding another entry here. in @@ -212,4 +213,100 @@ getdns_return_t getdns_pubkey_pinset_sanity_check( return GETDNS_RETURN_GENERIC_ERROR; return GETDNS_RETURN_GOOD; } + +getdns_return_t +_getdns_get_pubkey_pinset_from_list(const getdns_list *pinset_list, + struct mem_funcs *mf, + sha256_pin_t **pinset_out) +{ + getdns_return_t r; + size_t pins, i; + sha256_pin_t *out = NULL, *onext = NULL; + getdns_dict * pin; + getdns_bindata * data = NULL; + + if (r = getdns_list_get_length(pinset_list, &pins), r) + return r; + for (i = 0; i < pins; i++) + { + if (r = getdns_list_get_dict(pinset_list, i, &pin), r) + goto fail; + /* does the pin have the right digest type? */ + if (r = getdns_dict_get_bindata(pin, "digest", &data), r) + goto fail; + if (data->size != sha256.size || + memcmp(data->data, sha256.data, sha256.size)) { + r = GETDNS_RETURN_INVALID_PARAMETER; + goto fail; + } + /* if it does, is the value the right length? */ + if (r = getdns_dict_get_bindata(pin, "value", &data), r) + goto fail; + if (data->size != SHA256_DIGEST_LENGTH) { + r = GETDNS_RETURN_INVALID_PARAMETER; + goto fail; + } + /* make a new pin */ + onext = GETDNS_MALLOC(*mf, sha256_pin_t); + if (onext == NULL) { + r = GETDNS_RETURN_MEMORY_ERROR; + goto fail; + } + onext->next = out; + memcpy(onext->pin, data->data, SHA256_DIGEST_LENGTH); + out = onext; + } + + *pinset_out = out; + return GETDNS_RETURN_GOOD; + fail: + while (out) { + onext = out->next; + GETDNS_FREE(*mf, out); + out = onext; + } + return r; +} + +getdns_return_t +_getdns_get_pubkey_pinset_list(getdns_context *ctx, + const sha256_pin_t *pinset_in, + getdns_list **pinset_list) +{ + getdns_list *out = getdns_list_create_with_context(ctx); + getdns_return_t r; + uint8_t buf[SHA256_DIGEST_LENGTH]; + getdns_bindata value = { .size = SHA256_DIGEST_LENGTH, .data = buf }; + getdns_dict *pin = NULL; + size_t idx = 0; + + if (out == NULL) + return GETDNS_RETURN_MEMORY_ERROR; + while (pinset_in) { + pin = getdns_dict_create_with_context(ctx); + if (pin == NULL) { + r = GETDNS_RETURN_MEMORY_ERROR; + goto fail; + } + if (r = getdns_dict_set_bindata(pin, "digest", &sha256), r) + goto fail; + memcpy(buf, pinset_in->pin, sizeof(buf)); + if (r = getdns_dict_set_bindata(pin, "value", &value), r) + goto fail; + if (r = getdns_list_set_dict(out, idx++, pin), r) + goto fail; + getdns_dict_destroy(pin); + pin = NULL; + pinset_in = pinset_in->next; + } + + *pinset_list = out; + return GETDNS_RETURN_GOOD; + fail: + getdns_dict_destroy(pin); + getdns_list_destroy(out); + return r; +} + + /* pubkey-pinning.c */ diff --git a/src/pubkey-pinning.h b/src/pubkey-pinning.h new file mode 100644 index 00000000..3b5a5983 --- /dev/null +++ b/src/pubkey-pinning.h @@ -0,0 +1,53 @@ +/** + * + * /brief internal functions for dealing with pubkey pinsets + * + */ + +/* + * Copyright (c) 2015 ACLU + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the names of the copyright holders nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PUBKEY_PINNING_H_ +#define PUBKEY_PINNING_H_ + + +/* create and populate a pinset linked list from a getdns_list pinset */ +getdns_return_t +_getdns_get_pubkey_pinset_from_list(const getdns_list *pinset_list, + struct mem_funcs *mf, + sha256_pin_t **pinset_out); + + +/* create a getdns_list version of the pinset */ +getdns_return_t +_getdns_get_pubkey_pinset_list(getdns_context *ctx, + const sha256_pin_t *pinset_in, + getdns_list **pinset_list); + + +#endif +/* pubkey-pinning.h */ From 0d2256df09f6de38360752836fddafc0a5f084b5 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Mon, 21 Dec 2015 18:08:53 -0500 Subject: [PATCH 06/17] set and return the pubkey_pinsets on the upstream resolvers --- src/context.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/context.c b/src/context.c index 94a88f72..5e9a0b9d 100644 --- a/src/context.c +++ b/src/context.c @@ -55,6 +55,7 @@ #include "stub.h" #include "list.h" #include "dict.h" +#include "pubkey-pinning.h" #define GETDNS_PORT_ZERO 0 #define GETDNS_PORT_DNS 53 @@ -1950,6 +1951,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, upstream_init(upstream, upstreams, ai); upstream->transport = getdns_upstream_transports[j]; if (getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) { + getdns_list *pubkey_pinset = NULL; if ((r = getdns_dict_get_bindata( dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) { /*TODO: VALIDATE THIS STRING!*/ @@ -1958,6 +1960,16 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, tls_auth_name->size); upstream->tls_auth_name[tls_auth_name->size] = '\0'; } + 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? */ + r = _getdns_get_pubkey_pinset_from_list(pubkey_pinset, + &(upstreams->mf), + &(upstream->tls_pubkey_pinset)); + if (r != GETDNS_RETURN_GOOD) + goto invalid_parameter; + } } if ((upstream->tsig_alg = tsig_alg)) { if (tsig_name) { @@ -3170,11 +3182,19 @@ getdns_context_get_upstream_recursive_servers(getdns_context *context, (uint32_t)upstream_port(upstream)))) break; - if (upstream->transport == GETDNS_TRANSPORT_TLS && - upstream_port(upstream) != getdns_port_array[j] && - (r = getdns_dict_set_int(d, "tls_port", - (uint32_t)upstream_port(upstream)))) - break; + if (upstream->transport == GETDNS_TRANSPORT_TLS) { + if (upstream_port(upstream) == getdns_port_array[j]) + (void) getdns_dict_set_int(d, "tls_port", + (uint32_t) upstream_port(upstream)); + if (upstream->tls_pubkey_pinset) { + getdns_list *pins = NULL; + if (_getdns_get_pubkey_pinset_list(context, + upstream->tls_pubkey_pinset, + &pins) == GETDNS_RETURN_GOOD) + (void) getdns_dict_set_list(d, "tls_pubkey_pinset", pins); + getdns_list_destroy(pins); + } + } } if (!r) r = _getdns_list_append_dict(upstreams, d); From 614d317fd87b4888ff672576e9cd8918b911bb2c Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Sun, 20 Dec 2015 13:50:42 -0500 Subject: [PATCH 07/17] getdns_query: add -K option to attach pinsets to getdns_contexts. --- src/test/getdns_query.c | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 2d00c985..2f089a82 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -36,6 +36,8 @@ #define MAX_TIMEOUTS FD_SETSIZE +#define EXAMPLE_PIN "pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"" + /* Eventloop based on select */ typedef struct my_eventloop { getdns_eventloop base; @@ -260,6 +262,8 @@ static char *the_root = "."; static char *name; static getdns_context *context; static getdns_dict *extensions; +static getdns_list *pubkey_pinset = NULL; +static size_t pincount = 0; static uint16_t request_type = GETDNS_RRTYPE_NS; static int timeout, edns0_size, padding_blocksize; static int async = 0, interactive = 0; @@ -474,6 +478,8 @@ print_usage(FILE *out, const char *progname) fprintf(out, "\t-j\tOutput json response dict\n"); fprintf(out, "\t-J\tPretty print json response dict\n"); fprintf(out, "\t-k\tPrint root trust anchors\n"); + fprintf(out, "\t-K \tPin a public key for TLS connections (can repeat)\n"); + fprintf(out, "\t\t(should look like '" EXAMPLE_PIN "')\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"); @@ -681,6 +687,7 @@ getdns_return_t parse_args(int argc, char **argv) int t, print_api_info = 0, print_trust_anchors = 0; getdns_list *upstream_list = NULL; getdns_list *tas = NULL, *hints = NULL; + getdns_dict *pubkey_pin = NULL; size_t upstream_count = 0; FILE *fh; @@ -819,6 +826,36 @@ getdns_return_t parse_args(int argc, char **argv) case 'J': json = 1; break; + case 'K': + if (c[1] != 0 || ++i >= argc || !*argv[i]) { + fprintf(stderr, "pin string of the form " + EXAMPLE_PIN + "expected after -K\n"); + return GETDNS_RETURN_GENERIC_ERROR; + } + pubkey_pin = getdns_pubkey_pin_create_from_string(context, + argv[i]); + if (pubkey_pin == NULL) { + fprintf(stderr, "could not convert '%s' into a " + "public key pin.\n" + "Good pins look like: " EXAMPLE_PIN "\n" + "Please see RFC 7469 for details about " + "the format\n", argv[i]); + return GETDNS_RETURN_GENERIC_ERROR; + } + if (pubkey_pinset == NULL) + pubkey_pinset = getdns_list_create_with_context(context); + if (r = getdns_list_set_dict(pubkey_pinset, pincount++, + pubkey_pin), r) { + fprintf(stderr, "Failed to add pin to pinset (error %d: %s)\n", + r, getdns_get_errorstr_by_id(r)); + getdns_dict_destroy(pubkey_pin); + pubkey_pin = NULL; + return GETDNS_RETURN_GENERIC_ERROR; + } + getdns_dict_destroy(pubkey_pin); + pubkey_pin = NULL; + break; case 'k': print_trust_anchors = 1; break; @@ -979,6 +1016,20 @@ next: ; } if (r) return r; + if (pubkey_pinset && upstream_count) { + getdns_dict *upstream; + /* apply the accumulated pubkey pinset to all upstreams: */ + for (i = 0; i < upstream_count; i++) { + if (r = getdns_list_get_dict(upstream_list, i, &upstream), r) { + fprintf(stderr, "Failed to get upstream %lu when adding pinset\n", i); + return r; + } + if (r = getdns_dict_set_list(upstream, "tls_pubkey_pinset", pubkey_pinset), r) { + fprintf(stderr, "Failed to set pubkey pinset on upstream %lu\n", i); + return r; + } + } + } if (upstream_count && (r = getdns_context_set_upstream_recursive_servers( context, upstream_list))) { From d09675539ee23d9af85bd7e275cf4e7561897361 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Mon, 21 Dec 2015 19:27:40 -0500 Subject: [PATCH 08/17] Provide access to the pinsets during the TLS verification callback We do this by associating a getdns_upstream object with the SSL object handled by that upstream. This allows us to collapse the verification callback code to a single function. Note that if we've agreed that fallback is ok, we are now willing to accept *any* cert verification error, not just HOSTNAME_MISMATCH. This is fine, because the alternative is falling back to cleartext, which would be worse. We also always set SSL_VERIFY_PEER, since we might as well try to do so; we'll drop the verification error ourselves if we know we're OK with falling back. --- src/context.h | 1 + src/pubkey-pinning.c | 49 +++++++++++++++++++++++++++++++++++++ src/pubkey-pinning.h | 12 ++++++++++ src/stub.c | 57 ++++++++++++++++---------------------------- 4 files changed, 83 insertions(+), 36 deletions(-) diff --git a/src/context.h b/src/context.h index 729962ac..d814219c 100644 --- a/src/context.h +++ b/src/context.h @@ -149,6 +149,7 @@ typedef struct getdns_upstream { unsigned has_prev_client_cookie : 1; unsigned has_server_cookie : 1; unsigned server_cookie_len : 5; + unsigned tls_fallback_ok : 1; /* TSIG */ uint8_t tsig_dname[256]; diff --git a/src/pubkey-pinning.c b/src/pubkey-pinning.c index 96d37fe1..f2935dbb 100644 --- a/src/pubkey-pinning.c +++ b/src/pubkey-pinning.c @@ -308,5 +308,54 @@ _getdns_get_pubkey_pinset_list(getdns_context *ctx, return r; } +/* this should only happen once ever in the life of the library. it's + used to associate a getdns_context_t with an SSL_CTX, to be able to + do custom verification. + + see doc/HOWTO/proxy_certificates.txt as an example +*/ +static int +_get_ssl_getdns_upstream_idx() +{ + static volatile int idx = -1; + if (idx < 0) { + CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE); + if (idx < 0) + idx = SSL_get_ex_new_index(0, "associated getdns upstream", + NULL,NULL,NULL); + CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE); + } + return idx; +} + +getdns_upstream* +_getdns_upstream_from_x509_store(X509_STORE_CTX *store) +{ + int uidx = _get_ssl_getdns_upstream_idx(); + int sslidx = SSL_get_ex_data_X509_STORE_CTX_idx(); + const SSL *ssl; + + /* all *_get_ex_data() should return NULL on failure anyway */ + ssl = X509_STORE_CTX_get_ex_data(store, sslidx); + if (ssl) + return (getdns_upstream*) SSL_get_ex_data(ssl, uidx); + else + return NULL; + /* TODO: if we want more details about errors somehow, we + * might call ERR_get_error (see CRYPTO_set_ex_data(3ssl))*/ +} + +getdns_return_t +_getdns_associate_upstream_with_SSL(SSL *ssl, + getdns_upstream *upstream) +{ + int uidx = _get_ssl_getdns_upstream_idx(); + if (SSL_set_ex_data(ssl, uidx, upstream)) + return GETDNS_RETURN_GOOD; + else + return GETDNS_RETURN_GENERIC_ERROR; + /* TODO: if we want more details about errors somehow, we + * might call ERR_get_error (see CRYPTO_set_ex_data(3ssl))*/ +} /* pubkey-pinning.c */ diff --git a/src/pubkey-pinning.h b/src/pubkey-pinning.h index 3b5a5983..c5585567 100644 --- a/src/pubkey-pinning.h +++ b/src/pubkey-pinning.h @@ -48,6 +48,18 @@ _getdns_get_pubkey_pinset_list(getdns_context *ctx, const sha256_pin_t *pinset_in, getdns_list **pinset_list); + +/* internal functions for associating X.509 verification processes in + * OpenSSL with getdns_upstream objects. */ + +getdns_upstream* +_getdns_upstream_from_x509_store(X509_STORE_CTX *store); + + +getdns_return_t +_getdns_associate_upstream_with_SSL(SSL *ssl, + getdns_upstream *upstream); + #endif /* pubkey-pinning.h */ diff --git a/src/stub.c b/src/stub.c index 4576851e..44c0e58e 100644 --- a/src/stub.c +++ b/src/stub.c @@ -47,6 +47,7 @@ #include "context.h" #include "util-internal.h" #include "general.h" +#include "pubkey-pinning.h" #define STUB_OUT_OF_OPTIONS -5 /* upstream options exceeded MAXIMUM_UPSTREAM_OPTION_SPACE */ #define STUB_TLS_SETUP_ERROR -4 @@ -841,40 +842,20 @@ tls_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) { int tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { -#if defined(STUB_DEBUG) && STUB_DEBUG int err; - const char * err_str; - - err = X509_STORE_CTX_get_error(ctx); - err_str = X509_verify_cert_error_string(err); - DEBUG_STUB("--- %s, VERIFY RESULT: %s\n", __FUNCTION__, err_str); -#endif - /*Always proceed without changing result*/ - return preverify_ok; -} - -int -tls_verify_callback_with_fallback(int preverify_ok, X509_STORE_CTX *ctx) -{ -#ifdef X509_V_ERR_HOSTNAME_MISMATCH - int err; -# if defined(STUB_DEBUG) && STUB_DEBUG - const char * err_str; -# endif + getdns_upstream *upstream; err = X509_STORE_CTX_get_error(ctx); -# if defined(STUB_DEBUG) && STUB_DEBUG - err_str = X509_verify_cert_error_string(err); - DEBUG_STUB("--- %s, VERIFY RESULT: (%d) \"%s\"\n", __FUNCTION__, err, err_str); -# endif + upstream = _getdns_upstream_from_x509_store(ctx); + DEBUG_STUB("--- %s, VERIFY RESULT: (%d) \"%s\"\n", __FUNCTION__, + err, X509_verify_cert_error_string(err)); + +#ifdef X509_V_ERR_HOSTNAME_MISMATCH /*Proceed if error is hostname mismatch*/ - if (err == X509_V_ERR_HOSTNAME_MISMATCH) { + if (upstream && upstream->tls_fallback_ok && err == X509_V_ERR_HOSTNAME_MISMATCH) DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__); - return 1; - } - else #endif - return preverify_ok; + return (upstream && upstream->tls_fallback_ok) ? 1 : preverify_ok; } static SSL* @@ -892,11 +873,17 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) SSL_free(ssl); return NULL; } + /* make sure we'll be able to find the context again when we need it */ + if (_getdns_associate_upstream_with_SSL(ssl, upstream) != GETDNS_RETURN_GOOD) { + SSL_free(ssl); + return NULL; + } /* 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. */ + upstream->tls_fallback_ok = 0; /* If we have a hostname, always use it */ if (upstream->tls_auth_name[0] != '\0') { /*Request certificate for the auth_name*/ @@ -920,12 +907,8 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) } #endif /* Allow fallback to opportunistic 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_set_cipher_list(ssl, "DEFAULT"); - } + if (dnsreq->netreqs[0]->tls_auth_min != GETDNS_AUTHENTICATION_HOSTNAME) + upstream->tls_fallback_ok = 1; } else { /* Lack of host name is OK unless only authenticated TLS is specified*/ if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) { @@ -937,10 +920,12 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) /* no hostname verification, so we will make opportunistic connections */ 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_set_cipher_list(ssl, "DEFAULT"); + upstream->tls_fallback_ok = 1; } } + if (upstream->tls_fallback_ok) + SSL_set_cipher_list(ssl, "DEFAULT"); + SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback); SSL_set_connect_state(ssl); (void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); From a9eb9ccca9fe66172b818dc2bf4e9787ebeb4189 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Mon, 21 Dec 2015 21:23:13 -0500 Subject: [PATCH 09/17] Check that the pinset matches if it is configured if the upstream is configured to allow fallback, this will not be a fatal error, but it will still be checked. Future work: * verify any certs higher in the chain than the end-entity cert * deal with raw public keys * in the fallback case, report to the user whether the pinset match failed --- src/pubkey-pinning.c | 83 ++++++++++++++++++++++++++++++++++++++++++++ src/pubkey-pinning.h | 5 ++- src/stub.c | 10 ++++++ 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/pubkey-pinning.c b/src/pubkey-pinning.c index f2935dbb..2f685ad3 100644 --- a/src/pubkey-pinning.c +++ b/src/pubkey-pinning.c @@ -45,10 +45,13 @@ * given a such a pinset, we should be able to validate a chain * properly according to section 2.6 of RFC 7469. */ +#include "config.h" +#include "debug.h" #include #include #include #include +#include #include #include "context.h" @@ -358,4 +361,84 @@ _getdns_associate_upstream_with_SSL(SSL *ssl, * might call ERR_get_error (see CRYPTO_set_ex_data(3ssl))*/ } +getdns_return_t +_getdns_verify_pinset_match(const sha256_pin_t *pinset, + X509_STORE_CTX *store) +{ + getdns_return_t ret = GETDNS_RETURN_GENERIC_ERROR; + X509 *x; + int i, len; + unsigned char raw[4096]; + unsigned char *next = raw; + unsigned char buf[sizeof(pinset->pin)]; + const sha256_pin_t *p; + + if (pinset == NULL || store == NULL) + return GETDNS_RETURN_GENERIC_ERROR; + + /* start at the base of the chain (the end-entity cert) and + * make sure that some valid element of the chain does match + * the pinset. */ + + /* Testing with OpenSSL 1.0.1e-1 on debian indicates that + * store->untrusted holds the chain offered by the server in + * the order that the server offers it. If the server offers + * bogus certificates (that is, matching and valid certs that + * belong to private keys that the server does not control), + * the the verification will succeed (including this pinset + * check), but the handshake will fail outside of this + * verification. */ + + /* TODO: how do we handle raw public keys? */ + + for (i = 0; i < sk_X509_num(store->untrusted); i++) { + if (i > 0) { + /* TODO: how do we ensure that the certificates in + * each stage appropriately sign the previous one? + * for now, to be safe, we only examine the end-entity + * cert: */ + return GETDNS_RETURN_GENERIC_ERROR; + } + + x = sk_X509_value(store->untrusted, i); + if (x->cert_info == NULL) + continue; +#if defined(STUB_DEBUG) && STUB_DEBUG + DEBUG_STUB("--- %s: name of cert %d:\n", __FUNCTION__, i); + if (x->cert_info->subject != NULL) + X509_NAME_print_ex_fp(stderr, x->cert_info->subject, 4, XN_FLAG_ONELINE); + fprintf(stderr, "\n"); +#endif + if (x->cert_info->key == NULL) + continue; + + /* digest the cert with sha256 */ + len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), NULL); + if (len > sizeof(raw)) { + DEBUG_STUB("--- %s: pubkey %d is larger than %ld octets\n", + __FUNCTION__, i, sizeof(raw)); + continue; + } + i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), &next); + if (next - raw != len) { + DEBUG_STUB("--- %s: pubkey %d claimed it needed %d octets, really needed %ld\n", + __FUNCTION__, i, len, next - raw); + continue; + } + SHA256(raw, len, buf); + + /* compare it */ + for (p = pinset; p; p = p->next) + if (0 == memcmp(buf, p->pin, sizeof(p->pin))) { + DEBUG_STUB("--- %s: pubkey %d matched pin %p (%ld)!\n", + __FUNCTION__, i, p, sizeof(p->pin)); + return GETDNS_RETURN_GOOD; + } else + DEBUG_STUB("--- %s: pubkey %d did not match pin %p!\n", + __FUNCTION__, i, p); + } + + return ret; +} + /* pubkey-pinning.c */ diff --git a/src/pubkey-pinning.h b/src/pubkey-pinning.h index c5585567..894ccf00 100644 --- a/src/pubkey-pinning.h +++ b/src/pubkey-pinning.h @@ -60,6 +60,9 @@ getdns_return_t _getdns_associate_upstream_with_SSL(SSL *ssl, getdns_upstream *upstream); - +getdns_return_t +_getdns_verify_pinset_match(const sha256_pin_t *pinset, + X509_STORE_CTX *store); + #endif /* pubkey-pinning.h */ diff --git a/src/stub.c b/src/stub.c index 44c0e58e..98c12efb 100644 --- a/src/stub.c +++ b/src/stub.c @@ -844,6 +844,7 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { int err; getdns_upstream *upstream; + getdns_return_t pinset_ret = GETDNS_RETURN_GOOD; err = X509_STORE_CTX_get_error(ctx); upstream = _getdns_upstream_from_x509_store(ctx); @@ -855,6 +856,15 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) if (upstream && upstream->tls_fallback_ok && err == X509_V_ERR_HOSTNAME_MISMATCH) DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__); #endif + if (upstream && upstream->tls_pubkey_pinset) + pinset_ret = _getdns_verify_pinset_match(upstream->tls_pubkey_pinset, ctx); + + if (pinset_ret != GETDNS_RETURN_GOOD) { + DEBUG_STUB("--- %s, PINSET VALIDATION FAILURE!!\n", __FUNCTION__); + preverify_ok = 0; + if (upstream->tls_fallback_ok) + DEBUG_STUB("--- %s, PROCEEDING WITHOUT PINSET VALIDATION!!\n", __FUNCTION__); + } return (upstream && upstream->tls_fallback_ok) ? 1 : preverify_ok; } From 2ce806c05b8fa9909be87266970b9bb5b5cef688 Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Tue, 22 Dec 2015 15:12:25 +0000 Subject: [PATCH 10/17] Tinker with debug statements/comments. --- src/stub.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/stub.c b/src/stub.c index 98c12efb..e8663ece 100644 --- a/src/stub.c +++ b/src/stub.c @@ -852,9 +852,9 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) err, X509_verify_cert_error_string(err)); #ifdef X509_V_ERR_HOSTNAME_MISMATCH - /*Proceed if error is hostname mismatch*/ + /*Report if error is hostname mismatch*/ if (upstream && upstream->tls_fallback_ok && err == X509_V_ERR_HOSTNAME_MISMATCH) - DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__); + DEBUG_STUB("--- %s, PROCEEDING EVEN THOUGH HOSTNAME VALIDATION FAILED!!\n", __FUNCTION__); #endif if (upstream && upstream->tls_pubkey_pinset) pinset_ret = _getdns_verify_pinset_match(upstream->tls_pubkey_pinset, ctx); @@ -863,8 +863,10 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) DEBUG_STUB("--- %s, PINSET VALIDATION FAILURE!!\n", __FUNCTION__); preverify_ok = 0; if (upstream->tls_fallback_ok) - DEBUG_STUB("--- %s, PROCEEDING WITHOUT PINSET VALIDATION!!\n", __FUNCTION__); + DEBUG_STUB("--- %s, PROCEEDING EVEN THOUGH PINSET VALIDATION FAILED!!\n", __FUNCTION__); } + /* If fallback is allowed, proceed regardless of what the auth error is + (might not be hostname or pinset related) */ return (upstream && upstream->tls_fallback_ok) ? 1 : preverify_ok; } @@ -906,11 +908,10 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) 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__); + DEBUG_STUB("--- %s, ERROR: TLS Authentication functionality not available\n", __FUNCTION__); upstream->tls_hs_state = GETDNS_HS_FAILED; upstream->tls_auth_failed = 1; return NULL; @@ -922,21 +923,24 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) } 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__); + DEBUG_STUB("--- %s, ERROR: No host name provided for TLS authentication\n", __FUNCTION__); upstream->tls_hs_state = GETDNS_HS_FAILED; upstream->tls_auth_failed = 1; return NULL; } else { - /* no hostname verification, so we will make opportunistic connections */ - DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__); + /* no hostname verification, so we will make opportunistic connections */ + DEBUG_STUB("--- %s, PROCEEDING EVEN THOUGH NO HOSTNAME PROVIDED!!\n", __FUNCTION__); upstream->tls_auth_failed = 1; upstream->tls_fallback_ok = 1; } } - if (upstream->tls_fallback_ok) + if (upstream->tls_fallback_ok) { SSL_set_cipher_list(ssl, "DEFAULT"); + DEBUG_STUB("--- %s, PROCEEDING WITH OPPOTUNISTIC TLS CONNECTION (FALLBACK ALLOWED)!!\n", __FUNCTION__); + } else + DEBUG_STUB("--- %s, PROCEEDING WITH STRICT TLS CONNECTION!!\n", __FUNCTION__); SSL_set_verify(ssl, SSL_VERIFY_PEER, tls_verify_callback); - + SSL_set_connect_state(ssl); (void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); return ssl; From 792ecd65b81ba16fa3dbcdbc88f56a3adfec7924 Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Tue, 22 Dec 2015 15:24:56 +0000 Subject: [PATCH 11/17] Add missing constant to const-info.c --- src/const-info.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/const-info.c b/src/const-info.c index 3cfae20e..d1e81c80 100644 --- a/src/const-info.c +++ b/src/const-info.c @@ -69,6 +69,7 @@ static struct const_info consts_info[] = { { 618, "GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION", GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION_TEXT }, { 619, "GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE", GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE_TEXT }, { 620, "GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE", GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE_TEXT }, + { 621, "GETDNS_CONTEXT_CODE_PUBKEY_PINSET", GETDNS_CONTEXT_CODE_PUBKEY_PINSET_TEXT }, { 700, "GETDNS_CALLBACK_COMPLETE", GETDNS_CALLBACK_COMPLETE_TEXT }, { 701, "GETDNS_CALLBACK_CANCEL", GETDNS_CALLBACK_CANCEL_TEXT }, { 702, "GETDNS_CALLBACK_TIMEOUT", GETDNS_CALLBACK_TIMEOUT_TEXT }, From 77802808ce8e6c6a1fbe455e6e05ae9a8197e0f5 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 22 Dec 2015 15:39:22 -0500 Subject: [PATCH 12/17] rename GETDNS_AUTHENTICATION_HOSTNAME with GETDNS_AUTHENTICATION_REQUIRED --- src/const-info.c | 2 +- src/context.c | 6 +++--- src/getdns/getdns_extra.h.in | 5 +++-- src/stub.c | 8 ++++---- src/test/getdns_query.c | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/const-info.c b/src/const-info.c index d1e81c80..1288061c 100644 --- a/src/const-info.c +++ b/src/const-info.c @@ -90,7 +90,7 @@ static struct const_info consts_info[] = { { 1201, "GETDNS_TRANSPORT_TCP", GETDNS_TRANSPORT_TCP_TEXT }, { 1202, "GETDNS_TRANSPORT_TLS", GETDNS_TRANSPORT_TLS_TEXT }, { 1300, "GETDNS_AUTHENTICATION_NONE", GETDNS_AUTHENTICATION_NONE_TEXT }, - { 1301, "GETDNS_AUTHENTICATION_HOSTNAME", GETDNS_AUTHENTICATION_HOSTNAME_TEXT }, + { 1301, "GETDNS_AUTHENTICATION_REQUIRED", GETDNS_AUTHENTICATION_REQUIRED_TEXT }, }; static int const_info_cmp(const void *a, const void *b) diff --git a/src/context.c b/src/context.c index 5e9a0b9d..1d9feb8b 100644 --- a/src/context.c +++ b/src/context.c @@ -1487,7 +1487,7 @@ getdns_context_set_tls_authentication(getdns_context *context, { RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER); if (value != GETDNS_AUTHENTICATION_NONE && - value != GETDNS_AUTHENTICATION_HOSTNAME) { + value != GETDNS_AUTHENTICATION_REQUIRED) { return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; } context->tls_auth = value; @@ -2462,8 +2462,8 @@ _getdns_context_prepare_for_resolution(struct getdns_context *context, #endif } if (tls_only_is_in_transports_list(context) == 1 && - context->tls_auth == GETDNS_AUTHENTICATION_HOSTNAME) { - context->tls_auth_min = GETDNS_AUTHENTICATION_HOSTNAME; + context->tls_auth == GETDNS_AUTHENTICATION_REQUIRED) { + context->tls_auth_min = GETDNS_AUTHENTICATION_REQUIRED; /* TODO: If no auth data provided for any upstream, fail here */ } else { diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index dea756a6..cc679cf8 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -418,7 +418,8 @@ uint32_t getdns_get_api_version_number(void); /* Authentication options used when doing TLS */ typedef enum getdns_tls_authentication_t { GETDNS_AUTHENTICATION_NONE = 1300, - GETDNS_AUTHENTICATION_HOSTNAME = 1301, + GETDNS_AUTHENTICATION_REQUIRED = 1301, + GETDNS_AUTHENTICATION_HOSTNAME = 1301, /* an alias for REQUIRED */ } getdns_tls_authentication_t; /** @@ -426,7 +427,7 @@ typedef enum getdns_tls_authentication_t { * @{ */ #define GETDNS_AUTHENTICATION_NONE_TEXT "See getdns_context_set_tls_authentication()" -#define GETDNS_AUTHENTICATION_HOSTNAME_TEXT "See getdns_context_set_tls_authentication()" +#define GETDNS_AUTHENTICATION_REQUIRED_TEXT "See getdns_context_set_tls_authentication()" /** @} */ diff --git a/src/stub.c b/src/stub.c index e8663ece..4655f1b4 100644 --- a/src/stub.c +++ b/src/stub.c @@ -835,7 +835,7 @@ tls_failed(getdns_upstream *upstream) static int tls_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) { - return (netreq->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME && + return (netreq->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED && upstream->tls_auth_failed) ? 0 : 1; } @@ -909,7 +909,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); X509_VERIFY_PARAM_set1_host(param, upstream->tls_auth_name, 0); #else - if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) { + if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { /* TODO: Trigger post-handshake custom validation*/ DEBUG_STUB("--- %s, ERROR: TLS Authentication functionality not available\n", __FUNCTION__); upstream->tls_hs_state = GETDNS_HS_FAILED; @@ -918,11 +918,11 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) } #endif /* Allow fallback to opportunistic if settings permit it*/ - if (dnsreq->netreqs[0]->tls_auth_min != GETDNS_AUTHENTICATION_HOSTNAME) + if (dnsreq->netreqs[0]->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED) upstream->tls_fallback_ok = 1; } else { /* Lack of host name is OK unless only authenticated TLS is specified*/ - if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_HOSTNAME) { + if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { DEBUG_STUB("--- %s, ERROR: No host name provided for TLS authentication\n", __FUNCTION__); upstream->tls_hs_state = GETDNS_HS_FAILED; upstream->tls_auth_failed = 1; diff --git a/src/test/getdns_query.c b/src/test/getdns_query.c index 2f089a82..a0e36e8e 100644 --- a/src/test/getdns_query.c +++ b/src/test/getdns_query.c @@ -481,7 +481,7 @@ print_usage(FILE *out, const char *progname) fprintf(out, "\t-K \tPin a public key for TLS connections (can repeat)\n"); fprintf(out, "\t\t(should look like '" EXAMPLE_PIN "')\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-m\tSet TLS authentication mode to REQUIRED\n"); fprintf(out, "\t-p\tPretty print response dict\n"); fprintf(out, "\t-P \tPad TLS queries to a multiple of blocksize\n"); fprintf(out, "\t-r\tSet recursing resolution type\n"); @@ -865,7 +865,7 @@ getdns_return_t parse_args(int argc, char **argv) break; case 'm': getdns_context_set_tls_authentication(context, - GETDNS_AUTHENTICATION_HOSTNAME); + GETDNS_AUTHENTICATION_REQUIRED); break; case 'P': if (c[1] != 0 || ++i >= argc || !*argv[i]) { From 57a04f61dbd51f79c4de1ea19cd754aa81ee4b77 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 22 Dec 2015 16:13:14 -0500 Subject: [PATCH 13/17] Allow AUTHENTICATION_REQUIRED w/o hostname when pubkey pinset is available --- src/stub.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/stub.c b/src/stub.c index 4655f1b4..456194d3 100644 --- a/src/stub.c +++ b/src/stub.c @@ -921,12 +921,17 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) if (dnsreq->netreqs[0]->tls_auth_min != GETDNS_AUTHENTICATION_REQUIRED) upstream->tls_fallback_ok = 1; } else { - /* Lack of host name is OK unless only authenticated TLS is specified*/ + /* Lack of host name is OK unless only authenticated + * TLS is specified and we have no pubkey_pinset */ if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) { - DEBUG_STUB("--- %s, ERROR: No host name provided for TLS authentication\n", __FUNCTION__); - upstream->tls_hs_state = GETDNS_HS_FAILED; - upstream->tls_auth_failed = 1; - return NULL; + if (upstream->tls_pubkey_pinset) { + DEBUG_STUB("--- %s, PROCEEDING WITH ONLY PUBKEY PINNING AUTHENTICATION\n", __FUNCTION__); + } else { + DEBUG_STUB("--- %s, ERROR: No host name or pubkey pinset provided for TLS authentication\n", __FUNCTION__); + upstream->tls_hs_state = GETDNS_HS_FAILED; + upstream->tls_auth_failed = 1; + return NULL; + } } else { /* no hostname verification, so we will make opportunistic connections */ DEBUG_STUB("--- %s, PROCEEDING EVEN THOUGH NO HOSTNAME PROVIDED!!\n", __FUNCTION__); From 2a50f4d2ac17bd1b5f2d6843a264b3cab6d46c7b Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor Date: Tue, 22 Dec 2015 16:29:20 -0500 Subject: [PATCH 14/17] Set tls_auth_failed when any present authentication mechanism fails We used to only have hostnames available. now we have pubkey_pinsets available as well. We want upstream->tls_auth_failed to be 1 when any authentication mechanism we've been asked for fails (and also when we haven't been given any authentication mechanism at all). --- src/stub.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/stub.c b/src/stub.c index 456194d3..320300a6 100644 --- a/src/stub.c +++ b/src/stub.c @@ -862,6 +862,7 @@ tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) if (pinset_ret != GETDNS_RETURN_GOOD) { DEBUG_STUB("--- %s, PINSET VALIDATION FAILURE!!\n", __FUNCTION__); preverify_ok = 0; + upstream->tls_auth_failed = 1; if (upstream->tls_fallback_ok) DEBUG_STUB("--- %s, PROCEEDING EVEN THOUGH PINSET VALIDATION FAILED!!\n", __FUNCTION__); } @@ -1006,10 +1007,15 @@ tls_do_handshake(getdns_upstream *upstream) } upstream->tls_hs_state = GETDNS_HS_DONE; r = SSL_get_verify_result(upstream->tls_obj); + if (upstream->tls_auth_name[0]) #ifdef X509_V_ERR_HOSTNAME_MISMATCH - if (r == X509_V_ERR_HOSTNAME_MISMATCH) + if (r == X509_V_ERR_HOSTNAME_MISMATCH) +#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. */ #endif - upstream->tls_auth_failed = 1; + upstream->tls_auth_failed = 1; /* Reset timeout on success*/ GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); upstream->event.read_cb = NULL; From a5027981d9dcbdf25237954e6f52214a7fe43fe1 Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Wed, 23 Dec 2015 16:03:29 +0000 Subject: [PATCH 15/17] Change how the aliasing is done so the tpkg tests will pass --- src/getdns/getdns_extra.h.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index cc679cf8..ed56d735 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -418,10 +418,12 @@ uint32_t getdns_get_api_version_number(void); /* Authentication options used when doing TLS */ typedef enum getdns_tls_authentication_t { GETDNS_AUTHENTICATION_NONE = 1300, - GETDNS_AUTHENTICATION_REQUIRED = 1301, - GETDNS_AUTHENTICATION_HOSTNAME = 1301, /* an alias for REQUIRED */ + GETDNS_AUTHENTICATION_REQUIRED = 1301 } getdns_tls_authentication_t; +/* an alias for REQUIRED */ +#define GETDNS_AUTHENTICATION_HOSTNAME GETDNS_AUTHENTICATION_REQUIRED + /** * \defgroup Base authentication texts * @{ From 3afba25dade279ddd15bf9d3729acd1c108e211a Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Wed, 23 Dec 2015 17:50:10 +0000 Subject: [PATCH 16/17] Update test case and changeling --- ChangeLog | 8 ++++++++ src/test/tests_transports.sh | 17 +++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8d87442d..d7665bc7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,12 @@ * + * Update of unofficial extension to the API that supports stub mode + TLS verification. GETDNS_AUTHENTICATION_HOSTNAME is replaced by + GETDNS_AUTHENTICATION_REQUIRED (but remains available as an alias). + Upstreams can now be configured with either a hostname or a SPKI pinset + for TLS authentication (or both). If the GETDNS_AUTHENTICATION_REQUIRED + option is used at least one piece of authentication information must be + configured for each upstream, and all the configured authentication + information for an upstream must validate. * Remove STARTTLS implementation (no change to SPEC) * Enable TCP Fast Open when possible. Add OSX support for TFO. * Rename return_call_debugging to return_call_reporting diff --git a/src/test/tests_transports.sh b/src/test/tests_transports.sh index 9cf7f79d..8c23b51f 100755 --- a/src/test/tests_transports.sh +++ b/src/test/tests_transports.sh @@ -3,6 +3,8 @@ DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) SERVER_IP="8.8.8.8" TLS_SERVER_IP="185.49.141.38~getdnsapi.net" +TLS_SERVER_KEY="foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc9S=" +TLS_SERVER_WRONG_KEY="foxZRnIh9gZpWnl+zEiKa0EJ2rdCGroMWm02gaxSc1S=" GOOD_RESULT_SYNC="Status was: At least one response was returned" GOOD_RESULT_ASYNC="successfull" BAD_RESULT_SYNC="1 'Generic error'" @@ -59,26 +61,31 @@ usage () { echo " -s server configured for only TCP and UDP" echo " -t server configured for TLS, TCP and UDP" echo " (This must include the hostname e.g. 185.49.141.38~getdnsapi.net)" + echo " -k SPKI pin for server configured for TLS, TCP and UDP" } -while getopts ":p:s:t:dh" opt; do +while getopts ":p:s:t:k:dh" opt; do case $opt in d ) set -x ;; p ) DIR=$OPTARG ;; s ) SERVER_IP=$OPTARG ; echo "Setting server to $OPTARG" ;; t ) TLS_SERVER_IP=$OPTARG ; echo "Setting TLS server to $OPTARG" ;; + k ) TLS_SERVER_KEY=$OPTARG ; echo "Setting TLS server key to $OPTARG" ;; h ) usage ; exit ;; esac done TLS_SERVER_IP_NO_NAME=`echo ${TLS_SERVER_IP%~*}` echo $TLS_SERVER_IP_NO_NAME +TLS_SERVER_IP_WRONG_NAME=`echo ${TLS_SERVER_IP::${#TLS_SERVER_IP}-1}` 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_NO_NAME}" -"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP}") +"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP}" +"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} -K pin-sha256=\"${TLS_SERVER_KEY}\"" +"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP} -K pin-sha256=\"${TLS_SERVER_KEY}\"") GOOD_FALLBACK_QUERIES=( "-s -A -q getdnsapi.net -l LT @${SERVER_IP}" @@ -89,8 +96,10 @@ GOOD_FALLBACK_QUERIES=( "-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 L -m @${TLS_SERVER_IP_NO_NAME} " +"-s -A -q getdnsapi.net -l L @${SERVER_IP}" +"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_WRONG_NAME}" +"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME}" +"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} ${TLS_SERVER_WRONG_KEY}" "-s -G -q DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D") echo "Starting transport test" From f94798b2376f5278e634e904edbaa6feb7d13236 Mon Sep 17 00:00:00 2001 From: Sara Dickinson Date: Thu, 24 Dec 2015 10:00:15 +0000 Subject: [PATCH 17/17] Final mixups --- src/Makefile.in | 1 - src/test/tests_transports.sh | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index f1e23c8a..b380f67d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -326,7 +326,6 @@ libevent.lo libevent.o: $(srcdir)/extension/libevent.c config.h $(srcdir)/types- libmini_event.lo libmini_event.o: $(srcdir)/extension/libmini_event.c config.h $(srcdir)/debug.h config.h \ $(srcdir)/types-internal.h getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h \ $(srcdir)/util/rbtree.h $(srcdir)/extension/libmini_event.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h -<<<<<<< HEAD libuv.lo libuv.o: $(srcdir)/extension/libuv.c config.h $(srcdir)/debug.h config.h $(srcdir)/types-internal.h \ getdns/getdns.h getdns/getdns_extra.h getdns/getdns.h $(srcdir)/util/rbtree.h \ $(srcdir)/getdns/getdns_ext_libuv.h getdns/getdns_extra.h diff --git a/src/test/tests_transports.sh b/src/test/tests_transports.sh index 8c23b51f..68b80568 100755 --- a/src/test/tests_transports.sh +++ b/src/test/tests_transports.sh @@ -85,7 +85,8 @@ GOOD_QUERIES=( "-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 L -m @${TLS_SERVER_IP_NO_NAME} -K pin-sha256=\"${TLS_SERVER_KEY}\"" -"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP} -K pin-sha256=\"${TLS_SERVER_KEY}\"") +"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP} -K pin-sha256=\"${TLS_SERVER_KEY}\"" +"-s -G -q DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D") GOOD_FALLBACK_QUERIES=( "-s -A -q getdnsapi.net -l LT @${SERVER_IP}" @@ -99,8 +100,8 @@ NOT_AVAILABLE_QUERIES=( "-s -A -q getdnsapi.net -l L @${SERVER_IP}" "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_WRONG_NAME}" "-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME}" -"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} ${TLS_SERVER_WRONG_KEY}" -"-s -G -q DNSKEY getdnsapi.net -l U @${SERVER_IP} -b 512 -D") +"-s -A -q getdnsapi.net -l L -m @${TLS_SERVER_IP_NO_NAME} ${TLS_SERVER_WRONG_KEY}") + echo "Starting transport test" echo