Add ability to verify server certificate using hostname for TLS/STARTTLS

NOTE: This implementation will only work for OpenSSL v1.0.2 and later.
Doing it for earlier versions is totally insane:

  https://wiki.openssl.org/index.php/Hostname_validation
This commit is contained in:
saradickinson 2015-07-19 13:18:38 +02:00 committed by Sara Dickinson
parent 8beace7036
commit cb1dff1ac7
4 changed files with 38 additions and 4 deletions

View File

@ -605,6 +605,7 @@ upstream_init(getdns_upstream *upstream,
upstream->starttls_req = NULL;
upstream->transport = GETDNS_TRANSPORT_TCP;
upstream->tls_hs_state = GETDNS_HS_NONE;
upstream->tls_auth_name[0] = '\0';
upstream->tcp.write_error = 0;
upstream->loop = NULL;
(void) getdns_eventloop_event_init(
@ -1216,6 +1217,8 @@ getdns_set_base_dns_transports(
if (!context || transport_count == 0 || transports == NULL)
return GETDNS_RETURN_INVALID_PARAMETER;
/* TODO: restrict the use of each transport to once ->
sane list and correct max size for array*/
for(i=0; i<transport_count; i++)
{
if( transports[i] != GETDNS_TRANSPORT_UDP
@ -1662,6 +1665,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
getdns_dict *dict;
getdns_bindata *address_type;
getdns_bindata *address_data;
getdns_bindata *tls_auth_name;
struct sockaddr_storage addr;
getdns_bindata *scope_id;
@ -1735,6 +1739,16 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
upstream->addr.ss_family = addr.ss_family;
upstream_init(upstream, upstreams, ai);
upstream->transport = getdns_upstream_transports[j];
if (getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) {
if ((r = getdns_dict_get_bindata(
dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) {
/*TODO: VALIDATE THIS STRING!*/
memcpy(upstream->tls_auth_name,
(char *)tls_auth_name->data,
tls_auth_name->size);
upstream->tls_auth_name[tls_auth_name->size] = '\0';
}
}
upstreams->count++;
freeaddrinfo(ai);
}
@ -2130,11 +2144,14 @@ getdns_context_prepare_for_resolution(struct getdns_context *context,
#endif
if(context->tls_ctx == NULL)
return GETDNS_RETURN_BAD_CONTEXT;
SSL_CTX_set_verify(context->tls_ctx, SSL_VERIFY_PEER, NULL);
if (!SSL_CTX_set_default_verify_paths(context->tls_ctx))
return GETDNS_RETURN_BAD_CONTEXT;
}
}
/* Block use of STARTTLS/TLS ONLY in recursive mode as it won't work */
/* Note: If TLS is used in recursive mode this will try TLS on port
* 53 so it is blocked here. So is STARTTLS only at the moment. */
* 53 so it is blocked here. So is 'STARTTLS only' at the moment. */
if (context->resolution_type == GETDNS_RESOLUTION_RECURSING &&
context->dns_transport_count == 1 &&
(context->dns_transports[0] == GETDNS_TRANSPORT_TLS ||

View File

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

View File

@ -32,6 +32,7 @@
*/
#include <openssl/err.h>
#include <openssl/x509v3.h>
#include "config.h"
#include <fcntl.h>
#include "stub.h"
@ -822,12 +823,14 @@ tls_failed(getdns_upstream *upstream)
}
static SSL*
tls_create_object(getdns_context *context, int fd)
tls_create_object(getdns_context *context, int fd, const char* auth_name)
{
/* Create SSL instance */
if (context->tls_ctx == NULL)
return NULL;
SSL* ssl = SSL_new(context->tls_ctx);
X509_VERIFY_PARAM *param;
if(!ssl)
return NULL;
/* Connect the SSL object with a file descriptor */
@ -835,6 +838,10 @@ tls_create_object(getdns_context *context, int fd)
SSL_free(ssl);
return NULL;
}
SSL_set_tlsext_host_name(ssl, auth_name);
param = SSL_get0_param(ssl);
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set1_host(param, auth_name, 0);
SSL_set_connect_state(ssl);
(void) SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
return ssl;
@ -1302,7 +1309,8 @@ upstream_read_cb(void *userarg)
dnsreq = netreq->owner;
if (is_starttls_response(netreq)) {
upstream->tls_obj = tls_create_object(dnsreq->context,
upstream->fd);
upstream->fd,
upstream->tls_auth_name);
if (upstream->tls_obj == NULL)
upstream->tls_hs_state = GETDNS_HS_FAILED;
upstream->tls_hs_state = GETDNS_HS_WRITE;
@ -1542,7 +1550,7 @@ upstream_connect(getdns_upstream *upstream, getdns_transport_list_t transport,
return upstream->fd;
fd = tcp_connect(upstream, transport);
if (fd == -1) return -1;
upstream->tls_obj = tls_create_object(dnsreq->context, fd);
upstream->tls_obj = tls_create_object(dnsreq->context, fd, upstream->tls_auth_name);
if (upstream->tls_obj == NULL) {
close(fd);
return -1;

View File

@ -55,6 +55,7 @@ ipaddr_dict(getdns_context *context, char *ipstr)
char *s = strchr(ipstr, '%'), *scope_id_str = "";
char *p = strchr(ipstr, '@'), *portstr = "";
char *t = strchr(ipstr, '#'), *tls_portstr = "";
char *n = strchr(ipstr, '~'), *tls_namestr = "";
uint8_t buf[sizeof(struct in6_addr)];
getdns_bindata addr;
@ -73,6 +74,10 @@ ipaddr_dict(getdns_context *context, char *ipstr)
*t = 0;
tls_portstr = t + 1;
}
if (n) {
*n = 0;
tls_namestr = n + 1;
}
if (strchr(ipstr, ':')) {
getdns_dict_util_set_string(r, "address_type", "IPv6");
addr.size = 16;
@ -93,6 +98,9 @@ ipaddr_dict(getdns_context *context, char *ipstr)
getdns_dict_set_int(r, "port", (int32_t)atoi(portstr));
if (*tls_portstr)
getdns_dict_set_int(r, "tls_port", (int32_t)atoi(tls_portstr));
if (*tls_namestr) {
getdns_dict_util_set_string(r, "tls_auth_name", tls_namestr);
}
if (*scope_id_str)
getdns_dict_util_set_string(r, "scope_id", scope_id_str);