Block authenticated requests on unauthenticated connection

This commit is contained in:
Sara Dickinson 2015-09-29 12:09:39 +01:00
parent af617e92a7
commit 6b4ee4ed31
3 changed files with 33 additions and 21 deletions

View File

@ -567,8 +567,10 @@ _getdns_upstream_shutdown(getdns_upstream *upstream)
upstream->tcp.write_error = 0; upstream->tcp.write_error = 0;
upstream->writes_done = 0; upstream->writes_done = 0;
upstream->responses_received = 0; upstream->responses_received = 0;
if (upstream->tls_hs_state != GETDNS_HS_FAILED) if (upstream->tls_hs_state != GETDNS_HS_FAILED) {
upstream->tls_hs_state = GETDNS_HS_NONE; upstream->tls_hs_state = GETDNS_HS_NONE;
upstream->tls_auth_failed = 0;
}
/* Now TLS stuff*/ /* Now TLS stuff*/
if (upstream->tls_obj != NULL) { if (upstream->tls_obj != NULL) {
SSL_shutdown(upstream->tls_obj); SSL_shutdown(upstream->tls_obj);
@ -627,6 +629,7 @@ upstream_init(getdns_upstream *upstream,
upstream->starttls_req = NULL; upstream->starttls_req = NULL;
upstream->transport = GETDNS_TRANSPORT_TCP; upstream->transport = GETDNS_TRANSPORT_TCP;
upstream->tls_hs_state = GETDNS_HS_NONE; upstream->tls_hs_state = GETDNS_HS_NONE;
upstream->tls_auth_failed = 0;
upstream->tls_auth_name[0] = '\0'; upstream->tls_auth_name[0] = '\0';
upstream->tcp.write_error = 0; upstream->tcp.write_error = 0;
upstream->loop = NULL; upstream->loop = NULL;

View File

@ -102,6 +102,7 @@ typedef struct getdns_upstream {
getdns_eventloop *loop; getdns_eventloop *loop;
getdns_tcp_state tcp; getdns_tcp_state tcp;
char tls_auth_name[256]; char tls_auth_name[256];
size_t tls_auth_failed;
/* Pipelining of TCP network requests */ /* Pipelining of TCP network requests */
getdns_network_req *write_queue; getdns_network_req *write_queue;

View File

@ -819,7 +819,14 @@ tls_failed(getdns_upstream *upstream)
/* No messages should be scheduled onto an upstream in this state */ /* No messages should be scheduled onto an upstream in this state */
return ((upstream->transport == GETDNS_TRANSPORT_TLS || return ((upstream->transport == GETDNS_TRANSPORT_TLS ||
upstream->transport == GETDNS_TRANSPORT_STARTTLS) && upstream->transport == GETDNS_TRANSPORT_STARTTLS) &&
upstream->tls_hs_state == GETDNS_HS_FAILED) ? 1: 0; upstream->tls_hs_state == GETDNS_HS_FAILED) ? 1 : 0;
}
static int
tls_auth_status_ok(getdns_upstream *upstream, getdns_network_req *netreq) {
return (netreq->tls_auth_req &&
!netreq->tls_auth_fallback_ok &&
upstream->tls_auth_failed) ? 0 : 1;
} }
int int
@ -828,21 +835,23 @@ _getdns_tls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
err = X509_STORE_CTX_get_error(ctx); err = X509_STORE_CTX_get_error(ctx);
const char * err_str; const char * err_str;
err_str = X509_verify_cert_error_string(err); err_str = X509_verify_cert_error_string(err);
DEBUG_STUB("--- %s, ERROR: %s\n", __FUNCTION__, err_str); DEBUG_STUB("--- %s, VERIFY RESULT: %s\n", __FUNCTION__, err_str);
/*Always proceed without changing result*/ /*Always proceed without changing result*/
return preverify_ok; return preverify_ok;
} }
int int
_getdns_tls_verify_callback_with_fallback(int preverify_ok, X509_STORE_CTX *ctx) { tls_verify_callback_with_fallback(int preverify_ok, X509_STORE_CTX *ctx) {
int err; int err;
err = X509_STORE_CTX_get_error(ctx); err = X509_STORE_CTX_get_error(ctx);
const char * err_str; const char * err_str;
err_str = X509_verify_cert_error_string(err); err_str = X509_verify_cert_error_string(err);
DEBUG_STUB("--- %s, ERROR: (%d) \"%s\"\n", __FUNCTION__, err, err_str); DEBUG_STUB("--- %s, VERIFY RESULT: (%d) \"%s\"\n", __FUNCTION__, err, err_str);
/*Proceed if error is hostname mismatch*/ /*Proceed if error is hostname mismatch*/
if (err == X509_V_ERR_HOSTNAME_MISMATCH) if (err == X509_V_ERR_HOSTNAME_MISMATCH) {
DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__);
return 1; return 1;
}
else else
return preverify_ok; return preverify_ok;
} }
@ -875,6 +884,8 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
upstream->tls_hs_state = GETDNS_HS_FAILED; upstream->tls_hs_state = GETDNS_HS_FAILED;
return NULL; return NULL;
} else { } else {
DEBUG_STUB("--- %s, PROCEEDING WITHOUT HOSTNAME VALIDATION!!\n", __FUNCTION__);
upstream->tls_auth_failed = 1;
SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
} }
} else { } else {
@ -898,7 +909,7 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream)
#endif #endif
/* Allow fallback from authenticated TLS if settings permit it (use NONE here?)*/ /* Allow fallback from authenticated TLS if settings permit it (use NONE here?)*/
if (dnsreq->netreqs[0]->tls_auth_fallback_ok) if (dnsreq->netreqs[0]->tls_auth_fallback_ok)
SSL_set_verify(ssl, SSL_VERIFY_NONE, _getdns_tls_verify_callback_with_fallback); SSL_set_verify(ssl, SSL_VERIFY_NONE, tls_verify_callback_with_fallback);
} }
SSL_set_connect_state(ssl); SSL_set_connect_state(ssl);
@ -960,17 +971,13 @@ tls_do_handshake(getdns_upstream *upstream)
} }
} }
upstream->tls_hs_state = GETDNS_HS_DONE; upstream->tls_hs_state = GETDNS_HS_DONE;
/* TODO: Can we detect the authentication state of the connection here?*/ r = SSL_get_verify_result(upstream->tls_obj);
if (r == X509_V_ERR_HOSTNAME_MISMATCH)
upstream->tls_auth_failed = 1;
//#ifndef HAVE_SSL_HN_AUTH //#ifndef HAVE_SSL_HN_AUTH
/*TODO: When OpenSSL 1.0.2 not available, use custom function to validate /*TODO: When OpenSSL 1.0.2 not available, use custom function to validate
the hostname.*/ the hostname e.g. see libcurl:openssl.c:verifyhost() */
// X509* cert = SSL_get_peer_certificate(upstream->tls_obj); //#endif
// if(cert) { X509_free(cert); } /* Free immediately */
// if(NULL == cert) return 0;
// if (!verify_cert_hostname(cert, upstream->tls_auth_name))
// DEBUG_STUB("--- %s %s\n", __FUNCTION__, "Hostname verification failed: ");
// X509_free(cert);
//#endif
/* Reset timeout on success*/ /* Reset timeout on success*/
GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event); GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
upstream->event.read_cb = NULL; upstream->event.read_cb = NULL;
@ -1517,7 +1524,8 @@ netreq_upstream_write_cb(void *userarg)
static int static int
upstream_transport_valid(getdns_upstream *upstream, upstream_transport_valid(getdns_upstream *upstream,
getdns_transport_list_t transport) getdns_transport_list_t transport,
getdns_network_req *netreq)
{ {
/* Single shot UDP, uses same upstream as plain TCP. */ /* Single shot UDP, uses same upstream as plain TCP. */
if (transport == GETDNS_TRANSPORT_UDP) if (transport == GETDNS_TRANSPORT_UDP)
@ -1538,7 +1546,7 @@ upstream_transport_valid(getdns_upstream *upstream,
/* Otherwise, transport must match, and not have failed */ /* Otherwise, transport must match, and not have failed */
if (upstream->transport != transport) if (upstream->transport != transport)
return 0; return 0;
if (tls_failed(upstream)) if (tls_failed(upstream) || !tls_auth_status_ok(upstream, netreq))
return 0; return 0;
return 1; return 1;
} }
@ -1566,7 +1574,7 @@ upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport)
DEBUG_STUB(" current upstream: %d of %d \n",(int)i, (int)upstreams->count); DEBUG_STUB(" current upstream: %d of %d \n",(int)i, (int)upstreams->count);
do { do {
if (upstreams->upstreams[i].to_retry > 0 && if (upstreams->upstreams[i].to_retry > 0 &&
upstream_transport_valid(&upstreams->upstreams[i], transport)) { upstream_transport_valid(&upstreams->upstreams[i], transport, netreq)) {
upstreams->current = i; upstreams->current = i;
DEBUG_STUB(" selected upstream: %d\n",(int)i); DEBUG_STUB(" selected upstream: %d\n",(int)i);
return &upstreams->upstreams[i]; return &upstreams->upstreams[i];
@ -1578,11 +1586,11 @@ upstream_select(getdns_network_req *netreq, getdns_transport_list_t transport)
upstream = upstreams->upstreams; upstream = upstreams->upstreams;
for (i = 0; i < upstreams->count; i++) for (i = 0; i < upstreams->count; i++)
if (upstreams->upstreams[i].back_off < upstream->back_off && if (upstreams->upstreams[i].back_off < upstream->back_off &&
upstream_transport_valid(&upstreams->upstreams[i], transport)) upstream_transport_valid(&upstreams->upstreams[i], transport, netreq))
upstream = &upstreams->upstreams[i]; upstream = &upstreams->upstreams[i];
/* Need to check again that the transport is valid */ /* Need to check again that the transport is valid */
if (!upstream_transport_valid(upstream, transport)) { if (!upstream_transport_valid(upstream, transport, netreq)) {
DEBUG_STUB(" ! No valid upstream available\n"); DEBUG_STUB(" ! No valid upstream available\n");
return NULL; return NULL;
} }