mirror of https://github.com/getdnsapi/getdns.git
DANE records can be passed along each upstream with "dane_records" key
Needs to be printed as well
This commit is contained in:
parent
544746094c
commit
03bddb40e1
|
@ -611,6 +611,8 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams)
|
||||||
; upstreams->count--, upstream++ ) {
|
; upstreams->count--, upstream++ ) {
|
||||||
|
|
||||||
sha256_pin_t *pin = upstream->tls_pubkey_pinset;
|
sha256_pin_t *pin = upstream->tls_pubkey_pinset;
|
||||||
|
dane_record_t *dane_record = upstream->tls_dane_records;
|
||||||
|
|
||||||
if (upstream->loop && ( upstream->event.read_cb
|
if (upstream->loop && ( upstream->event.read_cb
|
||||||
|| upstream->event.write_cb
|
|| upstream->event.write_cb
|
||||||
|| upstream->event.timeout_cb) ) {
|
|| upstream->event.timeout_cb) ) {
|
||||||
|
@ -652,6 +654,12 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams)
|
||||||
pin = nextpin;
|
pin = nextpin;
|
||||||
}
|
}
|
||||||
upstream->tls_pubkey_pinset = NULL;
|
upstream->tls_pubkey_pinset = NULL;
|
||||||
|
while (dane_record) {
|
||||||
|
dane_record_t *next_dane_record = dane_record->next;
|
||||||
|
GETDNS_FREE(upstreams->mf, dane_record);
|
||||||
|
dane_record = next_dane_record;
|
||||||
|
}
|
||||||
|
upstream->tls_dane_records = NULL;
|
||||||
if (upstream->tls_cipher_list)
|
if (upstream->tls_cipher_list)
|
||||||
GETDNS_FREE(upstreams->mf, upstream->tls_cipher_list);
|
GETDNS_FREE(upstreams->mf, upstream->tls_cipher_list);
|
||||||
if (upstream->tls_ciphersuites)
|
if (upstream->tls_ciphersuites)
|
||||||
|
@ -966,6 +974,7 @@ upstream_init(getdns_upstream *upstream,
|
||||||
upstream->last_tls_auth_state = GETDNS_AUTH_NONE;
|
upstream->last_tls_auth_state = GETDNS_AUTH_NONE;
|
||||||
upstream->best_tls_auth_state = GETDNS_AUTH_NONE;
|
upstream->best_tls_auth_state = GETDNS_AUTH_NONE;
|
||||||
upstream->tls_pubkey_pinset = NULL;
|
upstream->tls_pubkey_pinset = NULL;
|
||||||
|
upstream->tls_dane_records = NULL;
|
||||||
upstream->loop = NULL;
|
upstream->loop = NULL;
|
||||||
(void) getdns_eventloop_event_init(
|
(void) getdns_eventloop_event_init(
|
||||||
&upstream->event, upstream, NULL, NULL, NULL);
|
&upstream->event, upstream, NULL, NULL, NULL);
|
||||||
|
@ -2786,6 +2795,52 @@ getdns_context_set_dnssec_allowed_skew(struct getdns_context *context,
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
} /* getdns_context_set_dnssec_allowed_skew */
|
} /* getdns_context_set_dnssec_allowed_skew */
|
||||||
|
|
||||||
|
static getdns_return_t
|
||||||
|
_getdns_list2dane_records(struct mem_funcs *mf, const getdns_list *dr_list,
|
||||||
|
dane_record_t **tls_dane_records)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
getdns_return_t r;
|
||||||
|
getdns_dict *dr_dict;
|
||||||
|
|
||||||
|
assert(tls_dane_records);
|
||||||
|
|
||||||
|
for (i = 0; !(r = getdns_list_get_dict(dr_list, i, &dr_dict)); i++) {
|
||||||
|
uint32_t usage;
|
||||||
|
uint32_t selector;
|
||||||
|
uint32_t type;
|
||||||
|
getdns_bindata *data;
|
||||||
|
getdns_dict *rdata;
|
||||||
|
dane_record_t *dane_record;
|
||||||
|
|
||||||
|
if (!getdns_dict_get_dict(dr_dict, "rdata", &rdata)) {
|
||||||
|
/* only scan TLSA RRs */
|
||||||
|
if (!getdns_dict_get_int(dr_dict, "type", &type)
|
||||||
|
&& type != GETDNS_RRTYPE_TLSA)
|
||||||
|
continue;
|
||||||
|
dr_dict = rdata;
|
||||||
|
}
|
||||||
|
if ((r = getdns_dict_get_int(dr_dict, "certificate_usage", &usage))
|
||||||
|
|| (r = getdns_dict_get_int(dr_dict, "selector", &selector))
|
||||||
|
|| (r = getdns_dict_get_int(dr_dict, "matching_type", &type))
|
||||||
|
|| (r = getdns_dict_get_bindata(dr_dict,
|
||||||
|
"certificate_association_data", &data)))
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!(dane_record = (dane_record_t *)GETDNS_XMALLOC(
|
||||||
|
*mf, uint8_t, sizeof(dane_record_t) + data->size)))
|
||||||
|
return GETDNS_RETURN_MEMORY_ERROR;
|
||||||
|
dane_record->next = *tls_dane_records;
|
||||||
|
dane_record->usage = (uint8_t)usage;
|
||||||
|
dane_record->selector = (uint8_t)selector;
|
||||||
|
dane_record->type = (uint8_t)type;
|
||||||
|
dane_record->size = data->size;
|
||||||
|
memcpy(dane_record->data, data->data, data->size);
|
||||||
|
*tls_dane_records = dane_record;
|
||||||
|
}
|
||||||
|
return r == GETDNS_RETURN_NO_SUCH_LIST_ITEM ? GETDNS_RETURN_GOOD : r;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* getdns_context_set_upstream_recursive_servers
|
* getdns_context_set_upstream_recursive_servers
|
||||||
*
|
*
|
||||||
|
@ -2992,6 +3047,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
||||||
upstream->transport = getdns_upstream_transports[j];
|
upstream->transport = getdns_upstream_transports[j];
|
||||||
if (dict && getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) {
|
if (dict && getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) {
|
||||||
getdns_list *pubkey_pinset = NULL;
|
getdns_list *pubkey_pinset = NULL;
|
||||||
|
getdns_list *dane_records = NULL;
|
||||||
getdns_bindata *tls_cipher_list = NULL;
|
getdns_bindata *tls_cipher_list = NULL;
|
||||||
getdns_bindata *tls_ciphersuites = NULL;
|
getdns_bindata *tls_ciphersuites = NULL;
|
||||||
getdns_bindata *tls_curves_list = NULL;
|
getdns_bindata *tls_curves_list = NULL;
|
||||||
|
@ -3031,6 +3087,30 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
|
||||||
goto invalid_parameter;
|
goto invalid_parameter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!(r = getdns_dict_get_list(
|
||||||
|
dict, "dane_records", &dane_records))) {
|
||||||
|
if ((r = _getdns_list2dane_records(
|
||||||
|
&(upstreams->mf), dane_records,
|
||||||
|
&(upstream->tls_dane_records)))) {
|
||||||
|
_getdns_upstream_log(upstream,
|
||||||
|
GETDNS_LOG_UPSTREAMS,
|
||||||
|
GETDNS_LOG_ERR,
|
||||||
|
"%-40s : Upstream : could"
|
||||||
|
" not parse dane_records: "
|
||||||
|
"%s\n", upstream->addr_str,
|
||||||
|
getdns_get_errorstr_by_id(r));
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
goto invalid_parameter;
|
||||||
|
}
|
||||||
|
} else if (r != GETDNS_RETURN_NO_SUCH_DICT_NAME)
|
||||||
|
_getdns_upstream_log(upstream,
|
||||||
|
GETDNS_LOG_UPSTREAMS,
|
||||||
|
GETDNS_LOG_ERR,
|
||||||
|
"%-40s : Upstream : could not "
|
||||||
|
"get dane_records: %s\n",
|
||||||
|
upstream->addr_str,
|
||||||
|
getdns_get_errorstr_by_id(r));
|
||||||
|
|
||||||
(void) getdns_dict_get_bindata(
|
(void) getdns_dict_get_bindata(
|
||||||
dict, "tls_cipher_list", &tls_cipher_list);
|
dict, "tls_cipher_list", &tls_cipher_list);
|
||||||
upstream->tls_cipher_list = tls_cipher_list
|
upstream->tls_cipher_list = tls_cipher_list
|
||||||
|
|
|
@ -132,6 +132,16 @@ typedef struct sha256_pin {
|
||||||
struct sha256_pin *next;
|
struct sha256_pin *next;
|
||||||
} sha256_pin_t;
|
} sha256_pin_t;
|
||||||
|
|
||||||
|
/* for doing DANE authentication of TLS-capable upstreams: */
|
||||||
|
typedef struct dane_record {
|
||||||
|
struct dane_record *next;
|
||||||
|
uint8_t usage;
|
||||||
|
uint8_t selector;
|
||||||
|
uint8_t type;
|
||||||
|
size_t size;
|
||||||
|
uint8_t data[];
|
||||||
|
} dane_record_t;
|
||||||
|
|
||||||
typedef struct getdns_upstream {
|
typedef struct getdns_upstream {
|
||||||
/* backpointer to containing upstreams structure */
|
/* backpointer to containing upstreams structure */
|
||||||
struct getdns_upstreams *upstreams;
|
struct getdns_upstreams *upstreams;
|
||||||
|
@ -223,6 +233,7 @@ typedef struct getdns_upstream {
|
||||||
/* Auth credentials */
|
/* Auth credentials */
|
||||||
char tls_auth_name[256];
|
char tls_auth_name[256];
|
||||||
sha256_pin_t *tls_pubkey_pinset;
|
sha256_pin_t *tls_pubkey_pinset;
|
||||||
|
dane_record_t *tls_dane_records;
|
||||||
|
|
||||||
/* When requests have been scheduled asynchronously on an upstream
|
/* When requests have been scheduled asynchronously on an upstream
|
||||||
* that is kept open, and a synchronous call is then done with the
|
* that is kept open, and a synchronous call is then done with the
|
||||||
|
|
|
@ -584,6 +584,8 @@ typedef enum getdns_loglevel_type {
|
||||||
#define GETDNS_LOG_INFO_TEXT "Informational message"
|
#define GETDNS_LOG_INFO_TEXT "Informational message"
|
||||||
#define GETDNS_LOG_DEBUG_TEXT "Debug-level message"
|
#define GETDNS_LOG_DEBUG_TEXT "Debug-level message"
|
||||||
|
|
||||||
|
#define GETDNS_LOG_UPSTREAMS 0x1000
|
||||||
|
#define GETDNS_LOG_UPSTREAMS_TEXT "Log messages about upstreams"
|
||||||
#define GETDNS_LOG_UPSTREAM_STATS 0x3000
|
#define GETDNS_LOG_UPSTREAM_STATS 0x3000
|
||||||
#define GETDNS_LOG_UPSTREAM_STATS_TEXT "Log messages about upstream statistics"
|
#define GETDNS_LOG_UPSTREAM_STATS_TEXT "Log messages about upstream statistics"
|
||||||
#define GETDNS_LOG_SYS_STUB 0x2000
|
#define GETDNS_LOG_SYS_STUB 0x2000
|
||||||
|
|
|
@ -995,6 +995,70 @@ getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* c
|
||||||
return GETDNS_RETURN_GOOD;
|
return GETDNS_RETURN_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getdns_return_t _getdns_tls_connection_set_dane_records(_getdns_tls_connection* conn, const char* auth_name, const dane_record_t* dane_records)
|
||||||
|
{
|
||||||
|
if (!conn || !conn->ssl || !auth_name)
|
||||||
|
return GETDNS_RETURN_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
#if 0 && defined(USE_DANESSL)
|
||||||
|
/* Stash auth name and pinset away for use in cert verification. */
|
||||||
|
conn->auth_name = auth_name;
|
||||||
|
conn->dane_records = dane_records;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_SSL_DANE_ENABLE)
|
||||||
|
int osr = SSL_dane_enable(conn->ssl, *auth_name ? auth_name : NULL);
|
||||||
|
(void) osr; /* unused parameter */
|
||||||
|
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_enable(\"%s\") -> %d\n"
|
||||||
|
, STUB_DEBUG_SETUP_TLS, __FUNC__, auth_name, osr);
|
||||||
|
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
|
||||||
|
const dane_record_t *dane_p;
|
||||||
|
size_t n_records= 0;
|
||||||
|
for (dane_p = dane_records; dane_p; dane_p = dane_p->next) {
|
||||||
|
osr = SSL_dane_tlsa_add(conn->ssl, dane_p->usage,
|
||||||
|
dane_p->selector, dane_p->type, dane_p->data, dane_p->size);
|
||||||
|
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_tlsa_add() -> %d\n"
|
||||||
|
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
|
||||||
|
if (osr > 0)
|
||||||
|
++n_records;
|
||||||
|
}
|
||||||
|
#elif 0 && defined(USE_DANESSL)
|
||||||
|
conn->pinset = pinset;
|
||||||
|
if (pinset) {
|
||||||
|
const char *auth_names[2] = { auth_name, NULL };
|
||||||
|
int osr = DANESSL_init(conn->ssl,
|
||||||
|
*auth_name ? auth_name : NULL,
|
||||||
|
*auth_name ? auth_names : NULL);
|
||||||
|
(void) osr; /* unused parameter */
|
||||||
|
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_init(\"%s\") -> %d\n"
|
||||||
|
, STUB_DEBUG_SETUP_TLS, __FUNC__, auth_name, osr);
|
||||||
|
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
|
||||||
|
const sha256_pin_t *pin_p;
|
||||||
|
size_t n_pins = 0;
|
||||||
|
for (pin_p = pinset; pin_p; pin_p = pin_p->next) {
|
||||||
|
osr = DANESSL_add_tlsa(conn->ssl, 3, 1, "sha256",
|
||||||
|
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
|
||||||
|
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n"
|
||||||
|
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
|
||||||
|
if (osr > 0)
|
||||||
|
++n_pins;
|
||||||
|
osr = DANESSL_add_tlsa(conn->ssl, 2, 1, "sha256",
|
||||||
|
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
|
||||||
|
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n"
|
||||||
|
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
|
||||||
|
if (osr > 0)
|
||||||
|
++n_pins;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error Must have either DANE SSL or OpenSSL v1.1.
|
||||||
|
#endif
|
||||||
|
return GETDNS_RETURN_GOOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getdns_return_t _getdns_tls_connection_certificate_verify(_getdns_tls_connection* conn, long* errnum, const char** errmsg)
|
getdns_return_t _getdns_tls_connection_certificate_verify(_getdns_tls_connection* conn, long* errnum, const char** errmsg)
|
||||||
{
|
{
|
||||||
if (!conn || !conn->ssl)
|
if (!conn || !conn->ssl)
|
||||||
|
|
|
@ -1049,8 +1049,9 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
||||||
/* Lack of host name is OK unless only authenticated
|
/* Lack of host name is OK unless only authenticated
|
||||||
* TLS is specified and we have no pubkey_pinset */
|
* TLS is specified and we have no pubkey_pinset */
|
||||||
if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) {
|
if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) {
|
||||||
if (upstream->tls_pubkey_pinset) {
|
if (upstream->tls_pubkey_pinset
|
||||||
DEBUG_STUB("%s %-35s: Proceeding with only pubkey pinning authentication\n",
|
|| upstream->tls_dane_records) {
|
||||||
|
DEBUG_STUB("%s %-35s: Proceeding with only pubkey pinning and/or DANE authentication\n",
|
||||||
STUB_DEBUG_SETUP_TLS, __FUNC__);
|
STUB_DEBUG_SETUP_TLS, __FUNC__);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_STUB("%s %-35s: ERROR:No auth name or pinset provided for this upstream for Strict TLS authentication\n",
|
DEBUG_STUB("%s %-35s: ERROR:No auth name or pinset provided for this upstream for Strict TLS authentication\n",
|
||||||
|
@ -1075,6 +1076,10 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
|
||||||
_getdns_tls_connection_set_host_pinset(
|
_getdns_tls_connection_set_host_pinset(
|
||||||
tls, upstream->tls_auth_name, upstream->tls_pubkey_pinset);
|
tls, upstream->tls_auth_name, upstream->tls_pubkey_pinset);
|
||||||
|
|
||||||
|
if (upstream->tls_dane_records)
|
||||||
|
_getdns_tls_connection_set_dane_records(
|
||||||
|
tls, upstream->tls_auth_name, upstream->tls_dane_records);
|
||||||
|
|
||||||
/* Session resumption. There are trade-offs here. Want to do it when
|
/* Session resumption. There are trade-offs here. Want to do it when
|
||||||
possible only if we have the right type of connection. Note a change
|
possible only if we have the right type of connection. Note a change
|
||||||
to the upstream auth info creates a new upstream so never re-uses.*/
|
to the upstream auth info creates a new upstream so never re-uses.*/
|
||||||
|
|
12
src/tls.h
12
src/tls.h
|
@ -43,6 +43,7 @@
|
||||||
/* Forward declare type. */
|
/* Forward declare type. */
|
||||||
struct sha256_pin;
|
struct sha256_pin;
|
||||||
struct getdns_log_config;
|
struct getdns_log_config;
|
||||||
|
struct dane_record;
|
||||||
|
|
||||||
/* Additional return codes required by TLS abstraction. Internal use only. */
|
/* Additional return codes required by TLS abstraction. Internal use only. */
|
||||||
#define GETDNS_RETURN_TLS_WANT_READ ((getdns_return_t) 420)
|
#define GETDNS_RETURN_TLS_WANT_READ ((getdns_return_t) 420)
|
||||||
|
@ -332,6 +333,17 @@ getdns_return_t _getdns_tls_connection_setup_hostname_auth(_getdns_tls_connectio
|
||||||
*/
|
*/
|
||||||
getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* conn, const char* auth_name, const struct sha256_pin* pinset);
|
getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* conn, const char* auth_name, const struct sha256_pin* pinset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set host pinset.
|
||||||
|
*
|
||||||
|
* @param conn the connection.
|
||||||
|
* @param auth_name the hostname.
|
||||||
|
* @param dane_records the DANE records that must match.
|
||||||
|
* @return GETDNS_RETURN_GOOD if all OK.
|
||||||
|
* @return GETDNS_RETURN_INVALID_PARAMETER if conn is null or has no SSL.
|
||||||
|
*/
|
||||||
|
getdns_return_t _getdns_tls_connection_set_dane_records(_getdns_tls_connection* conn, const char* auth_name, const struct dane_record* dane_records);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get result of certificate verification.
|
* Get result of certificate verification.
|
||||||
*
|
*
|
||||||
|
|
2
stubby
2
stubby
|
@ -1 +1 @@
|
||||||
Subproject commit 3d5632852826736b14a5b86b6f19117f7bce97da
|
Subproject commit a550394f874817bd5fda022c34c0c96e7f819bc2
|
Loading…
Reference in New Issue