DANE records can be passed along each upstream with "dane_records" key

Needs to be printed as well
This commit is contained in:
Willem Toorop 2022-10-03 13:21:36 +02:00
parent 544746094c
commit 03bddb40e1
7 changed files with 177 additions and 3 deletions

View File

@ -611,6 +611,8 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams)
; upstreams->count--, upstream++ ) {
sha256_pin_t *pin = upstream->tls_pubkey_pinset;
dane_record_t *dane_record = upstream->tls_dane_records;
if (upstream->loop && ( upstream->event.read_cb
|| upstream->event.write_cb
|| upstream->event.timeout_cb) ) {
@ -652,6 +654,12 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams)
pin = nextpin;
}
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)
GETDNS_FREE(upstreams->mf, upstream->tls_cipher_list);
if (upstream->tls_ciphersuites)
@ -966,6 +974,7 @@ upstream_init(getdns_upstream *upstream,
upstream->last_tls_auth_state = GETDNS_AUTH_NONE;
upstream->best_tls_auth_state = GETDNS_AUTH_NONE;
upstream->tls_pubkey_pinset = NULL;
upstream->tls_dane_records = NULL;
upstream->loop = NULL;
(void) getdns_eventloop_event_init(
&upstream->event, upstream, NULL, NULL, NULL);
@ -2786,6 +2795,52 @@ getdns_context_set_dnssec_allowed_skew(struct getdns_context *context,
return GETDNS_RETURN_GOOD;
} /* 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
*
@ -2992,6 +3047,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
upstream->transport = getdns_upstream_transports[j];
if (dict && getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) {
getdns_list *pubkey_pinset = NULL;
getdns_list *dane_records = NULL;
getdns_bindata *tls_cipher_list = NULL;
getdns_bindata *tls_ciphersuites = NULL;
getdns_bindata *tls_curves_list = NULL;
@ -3031,6 +3087,30 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
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(
dict, "tls_cipher_list", &tls_cipher_list);
upstream->tls_cipher_list = tls_cipher_list

View File

@ -132,6 +132,16 @@ typedef struct sha256_pin {
struct sha256_pin *next;
} 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 {
/* backpointer to containing upstreams structure */
struct getdns_upstreams *upstreams;
@ -223,6 +233,7 @@ typedef struct getdns_upstream {
/* Auth credentials */
char tls_auth_name[256];
sha256_pin_t *tls_pubkey_pinset;
dane_record_t *tls_dane_records;
/* When requests have been scheduled asynchronously on an upstream
* that is kept open, and a synchronous call is then done with the

View File

@ -584,6 +584,8 @@ typedef enum getdns_loglevel_type {
#define GETDNS_LOG_INFO_TEXT "Informational 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_TEXT "Log messages about upstream statistics"
#define GETDNS_LOG_SYS_STUB 0x2000

View File

@ -995,6 +995,70 @@ getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* c
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)
{
if (!conn || !conn->ssl)

View File

@ -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
* TLS is specified and we have no pubkey_pinset */
if (dnsreq->netreqs[0]->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) {
if (upstream->tls_pubkey_pinset) {
DEBUG_STUB("%s %-35s: Proceeding with only pubkey pinning authentication\n",
if (upstream->tls_pubkey_pinset
|| upstream->tls_dane_records) {
DEBUG_STUB("%s %-35s: Proceeding with only pubkey pinning and/or DANE authentication\n",
STUB_DEBUG_SETUP_TLS, __FUNC__);
} else {
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(
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
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.*/

View File

@ -43,6 +43,7 @@
/* Forward declare type. */
struct sha256_pin;
struct getdns_log_config;
struct dane_record;
/* Additional return codes required by TLS abstraction. Internal use only. */
#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);
/**
* 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.
*

2
stubby

@ -1 +1 @@
Subproject commit 3d5632852826736b14a5b86b6f19117f7bce97da
Subproject commit a550394f874817bd5fda022c34c0c96e7f819bc2