Skip to content

Commit

Permalink
fix only first host tried if cert validation fails
Browse files Browse the repository at this point in the history
  • Loading branch information
Fabian Mauchle committed Jul 21, 2021
1 parent b8f0cd6 commit 86220e7
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 96 deletions.
122 changes: 75 additions & 47 deletions dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,7 @@ void *dtlslistener(void *arg) {
ssl = SSL_new(ctx);
if (!ssl) {
pthread_mutex_unlock(&conf->tlsconf->lock);
debug(DBG_ERR, "dtlslistener: failed to create SSL connection");
continue;
}
bio = BIO_new_dgram(s, BIO_NOCLOSE);
Expand Down Expand Up @@ -517,12 +518,27 @@ void *dtlslistener(void *arg) {
} else {
free(params);
}
} else {
unsigned long error;
while ((error = ERR_get_error()))
debug(DBG_ERR, "dtlslistener: DTLS_listen failed: %s", ERR_error_string(error, NULL));
debug(DBG_ERR, "dtlslistener: DTLS_listen failed from %s", addr2string((struct sockaddr *)&from, tmp, sizeof(tmp)));
}
pthread_mutex_unlock(&conf->tlsconf->lock);
}
return NULL;
}

static void cleanup_connection(struct server *server) {
if (server->ssl)
SSL_shutdown(server->ssl);
if (server->sock >= 0)
close(server->sock);
if (server->ssl)
SSL_free(server->ssl);
server->ssl = NULL;
}

int dtlsconnect(struct server *server, int timeout, char *text) {
struct timeval socktimeout, now, start;
time_t wait;
Expand All @@ -534,6 +550,7 @@ int dtlsconnect(struct server *server, int timeout, char *text) {
BIO *bio;
struct addrinfo *source = NULL;
char *subj;
struct list_node *entry;

debug(DBG_DBG, "dtlsconnect: called from %s", text);
pthread_mutex_lock(&server->lock);
Expand All @@ -543,8 +560,6 @@ int dtlsconnect(struct server *server, int timeout, char *text) {

pthread_mutex_unlock(&server->lock);

hp = (struct hostportres *)list_first(server->conf->hostports)->data;

if(server->conf->source) {
source = resolvepassiveaddrinfo(server->conf->source, AF_UNSPEC, NULL, protodefs.socktype);
if(!source)
Expand All @@ -555,13 +570,7 @@ int dtlsconnect(struct server *server, int timeout, char *text) {

for (;;) {
/* ensure previous connection is properly closed */
if (server->ssl)
SSL_shutdown(server->ssl);
if (server->sock >= 0)
close(server->sock);
if (server->ssl)
SSL_free(server->ssl);
server->ssl = NULL;
cleanup_connection(server);

wait = connect_wait(start, server->connecttime, firsttry);
gettimeofday(&now, NULL);
Expand All @@ -570,55 +579,74 @@ int dtlsconnect(struct server *server, int timeout, char *text) {
if (source) freeaddrinfo(source);
return 0;
}
debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
if (wait) debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
sleep(wait);
firsttry = 0;

debug(DBG_INFO, "dtlsconnect: connecting to %s port %s", hp->host, hp->port);
for (entry = list_first(server->conf->hostports); entry; entry = list_next(entry)) {
hp = (struct hostportres *)entry->data;
debug(DBG_INFO, "dtlsconnect: trying to open DTLS connection to server %s (%s port %s)", server->conf->name, hp->host, hp->port);
if ((server->sock = bindtoaddr(source ? source : srcres, hp->addrinfo->ai_family, 0)) < 0) {
debug(DBG_ERR, "dtlsconnect: faild to bind socket for server %s (%s port %s)", server->conf->name, hp->host, hp->port);
goto concleanup;
}
if (connect(server->sock, hp->addrinfo->ai_addr, hp->addrinfo->ai_addrlen)) {
debug(DBG_ERR, "dtlsconnect: faild to connect socket for server %s (%s port %s)", server->conf->name, hp->host, hp->port);
goto concleanup;
}

if ((server->sock = bindtoaddr(source ? source : srcres, hp->addrinfo->ai_family, 0)) < 0)
continue;
if (connect(server->sock, hp->addrinfo->ai_addr, hp->addrinfo->ai_addrlen))
continue;
pthread_mutex_lock(&server->conf->tlsconf->lock);
if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))){
pthread_mutex_unlock(&server->conf->tlsconf->lock);
debug(DBG_ERR, "dtlsconnect: failed to get TLS context for server %s", server->conf->name);
goto concleanup;
}

pthread_mutex_lock(&server->conf->tlsconf->lock);
if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))){
server->ssl = SSL_new(ctx);
pthread_mutex_unlock(&server->conf->tlsconf->lock);
continue;
}

server->ssl = SSL_new(ctx);
pthread_mutex_unlock(&server->conf->tlsconf->lock);
if (!server->ssl)
continue;
if (!server->ssl) {
debug(DBG_ERR, "dtlsconnect: failed to create SSL conneciton for server %s", server->conf->name);
goto concleanup;
}

bio = BIO_new_dgram(server->sock, BIO_CLOSE);
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, hp->addrinfo->ai_addr);
SSL_set_bio(server->ssl, bio, bio);
if (sslconnecttimeout(server->ssl, 5) <= 0) {
while ((error = ERR_get_error()))
debug(DBG_ERR, "dtlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL));
debug(DBG_ERR, "dtlsconnect: SSL connect to %s failed", server->conf->name);
continue;
}
socktimeout.tv_sec = 5;
socktimeout.tv_usec = 0;
if (BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &socktimeout) == -1)
debug(DBG_WARN, "dtlsconnect: BIO_CTRL_DGRAM_SET_RECV_TIMEOUT failed");
bio = BIO_new_dgram(server->sock, BIO_CLOSE);
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, hp->addrinfo->ai_addr);
SSL_set_bio(server->ssl, bio, bio);
if (sslconnecttimeout(server->ssl, 5) <= 0) {
while ((error = ERR_get_error()))
debug(DBG_ERR, "dtlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL));
debug(DBG_ERR, "dtlsconnect: SSL connect to %s (%s port %s) failed", server->conf->name, hp->host, hp->port);
goto concleanup;
}
socktimeout.tv_sec = 5;
socktimeout.tv_usec = 0;
if (BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &socktimeout) == -1)
debug(DBG_WARN, "dtlsconnect: BIO_CTRL_DGRAM_SET_RECV_TIMEOUT failed");

cert = verifytlscert(server->ssl);
if (!cert) {
debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port);
goto concleanup;
}

cert = verifytlscert(server->ssl);
if (!cert)
continue;
if (verifyconfcert(cert, server->conf, hp)) {
subj = getcertsubject(cert);
if(subj) {
debug(DBG_WARN, "dtlsconnect: DTLS connection to %s, subject %s up", server->conf->name, subj);
free(subj);
if (verifyconfcert(cert, server->conf, hp)) {
subj = getcertsubject(cert);
if(subj) {
debug(DBG_WARN, "dtlsconnect: DTLS connection to %s (%s port %s), subject %s up", server->conf->name, hp->host, hp->port, subj);
free(subj);
}
X509_free(cert);
break;
} else {
debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port);
}
X509_free(cert);
break;

concleanup:
/* ensure previous connection is properly closed */
cleanup_connection(server);
}
X509_free(cert);
if (server->ssl) break;
}

pthread_mutex_lock(&server->lock);
Expand Down
20 changes: 16 additions & 4 deletions tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <pthread.h>
#include "radsecproxy.h"
#include "hostport.h"
#include "list.h"

#ifdef RADPROT_TCP
#include "debug.h"
Expand Down Expand Up @@ -84,6 +85,8 @@ int tcpconnect(struct server *server, int timeout, char *text) {
int firsttry = 1;
time_t wait;
struct addrinfo *source = NULL;
struct list_node *entry;
struct hostportres *hp;

debug(DBG_DBG, "tcpconnect: called from %s", text);
pthread_mutex_lock(&server->lock);
Expand Down Expand Up @@ -112,16 +115,25 @@ int tcpconnect(struct server *server, int timeout, char *text) {
if (source) freeaddrinfo(source);
return 0;
}
debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
if (wait) debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
sleep(wait);
firsttry = 0;


pthread_mutex_lock(&server->lock);

debug(DBG_INFO, "tcpconnect: connecting to %s", server->conf->name);
if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres, NULL)) < 0)
for (entry = list_first(server->conf->hostports); entry; entry = list_next(entry)) {
hp = (struct hostportres *)entry->data;
debug(DBG_INFO, "tcpconnect: trying to open TCP connection to server %s (%s port %s)", server->conf->name, hp->host, hp->port);
if ((server->sock = connecttcp(hp->addrinfo, source ? source : srcres, list_count(server->conf->hostports) > 1 ? 5 : 30)) >= 0) {
debug(DBG_WARN, "tcpconnect: TCP connection to server %s (%s port %s) up", hp->host, hp->port);
break;
}
}
if (server->sock < 0) {
debug(DBG_ERR, "tcpconnect: TCP connection to server %s failed", server->conf->name);
continue;
}

if (server->conf->keepalive)
enable_keepalive(server->sock);
break;
Expand Down
111 changes: 66 additions & 45 deletions tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@
#include <assert.h>
#include "radsecproxy.h"
#include "hostport.h"

#ifdef RADPROT_TLS
#include "debug.h"
#include "util.h"

#ifdef RADPROT_TLS

static void setprotoopts(struct commonprotoopts *opts);
static char **getlistenerargs();
void *tlslistener(void *arg);
Expand Down Expand Up @@ -82,6 +82,16 @@ void tlssetsrcres() {
AF_UNSPEC, NULL, protodefs.socktype);
}

static void cleanup_connection(struct server *server) {
if (server->ssl)
SSL_shutdown(server->ssl);
if (server->sock >= 0)
close(server->sock);
if (server->ssl)
SSL_free(server->ssl);
server->ssl = NULL;
}

int tlsconnect(struct server *server, int timeout, char *text) {
struct timeval now, start;
time_t wait;
Expand All @@ -92,7 +102,8 @@ int tlsconnect(struct server *server, int timeout, char *text) {
int origflags;
struct addrinfo *source = NULL;
char *subj;
struct hostportres *hpconnected = NULL;
struct list_node *entry;
struct hostportres *hp;

debug(DBG_DBG, "tlsconnect: called from %s", text);
pthread_mutex_lock(&server->lock);
Expand All @@ -109,23 +120,15 @@ int tlsconnect(struct server *server, int timeout, char *text) {
gettimeofday(&start, NULL);

for (;;) {
/* ensure previous connection is properly closed */
if (server->ssl)
SSL_shutdown(server->ssl);
if (server->sock >= 0)
close(server->sock);
if (server->ssl)
SSL_free(server->ssl);
server->ssl = NULL;

cleanup_connection(server);
wait = connect_wait(start, server->connecttime, firsttry);
gettimeofday(&now, NULL);
if (timeout && (now.tv_sec - start.tv_sec) + wait > timeout) {
debug(DBG_DBG, "tlsconnect: timeout");
if (source) freeaddrinfo(source);
return 0;
}
debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
if (wait) debug(DBG_INFO, "Next connection attempt to %s in %lds", server->conf->name, wait);
sleep(wait);
firsttry = 0;

Expand All @@ -136,46 +139,64 @@ int tlsconnect(struct server *server, int timeout, char *text) {
return 0;
}

debug(DBG_INFO, "tlsconnect: connecting to %s", server->conf->name);
if ((server->sock = connecttcphostlist(server->conf->hostports, source ? source : srcres, &hpconnected)) < 0)
continue;
if (server->conf->keepalive)
enable_keepalive(server->sock);
for (entry = list_first(server->conf->hostports); entry; entry = list_next(entry)) {
hp = (struct hostportres *)entry->data;
debug(DBG_INFO, "tlsconnect: trying to open TLS connection to server %s (%s port %s)", server->conf->name, hp->host, hp->port);
if ((server->sock = connecttcp(hp->addrinfo, source ? source : srcres, list_count(server->conf->hostports) > 1 ? 5 : 30)) < 0 ) {
debug(DBG_ERR, "tlsconnect: TLS connection to %s (%s port %s) failed: TCP connect failed", server->conf->name, hp->host, hp->port);
goto concleanup;
}

pthread_mutex_lock(&server->conf->tlsconf->lock);
if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))){
pthread_mutex_unlock(&server->conf->tlsconf->lock);
continue;
}
if (server->conf->keepalive)
enable_keepalive(server->sock);

server->ssl = SSL_new(ctx);
pthread_mutex_unlock(&server->conf->tlsconf->lock);
if (!server->ssl)
continue;
pthread_mutex_lock(&server->conf->tlsconf->lock);
if (!(ctx = tlsgetctx(handle, server->conf->tlsconf))) {
pthread_mutex_unlock(&server->conf->tlsconf->lock);
debug(DBG_ERR, "tlsconnect: failed to get TLS context for server %s", server->conf->name);
goto concleanup;
}

SSL_set_fd(server->ssl, server->sock);
if (sslconnecttimeout(server->ssl, 5) <= 0) {
while ((error = ERR_get_error()))
debug(DBG_ERR, "tlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL));
debug(DBG_ERR, "tlsconnect: SSL connect to %s failed", server->conf->name);
continue;
}
server->ssl = SSL_new(ctx);
pthread_mutex_unlock(&server->conf->tlsconf->lock);
if (!server->ssl) {
debug(DBG_ERR, "tlsconnect: failed to create SSL conneciton for server %s", server->conf->name);
goto concleanup;
}

SSL_set_fd(server->ssl, server->sock);
if (sslconnecttimeout(server->ssl, 5) <= 0) {
while ((error = ERR_get_error()))
debug(DBG_ERR, "tlsconnect: SSL connect to %s failed: %s", server->conf->name, ERR_error_string(error, NULL));
debug(DBG_ERR, "tlsconnect: SSL connect to %s (%s port %s) failed", server->conf->name, hp->host, hp->port);
goto concleanup;
}

cert = verifytlscert(server->ssl);
if (!cert)
continue;
if (verifyconfcert(cert, server->conf, hpconnected)) {
subj = getcertsubject(cert);
if(subj) {
debug(DBG_WARN, "tlsconnect: TLS connection to %s, subject %s up", server->conf->name, subj);
free(subj);
cert = verifytlscert(server->ssl);
if (!cert) {
debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port);
goto concleanup;
}

if (verifyconfcert(cert, server->conf, hp)) {
subj = getcertsubject(cert);
if(subj) {
debug(DBG_WARN, "tlsconnect: TLS connection to %s (%s port %s), subject %s up", server->conf->name, hp->host, hp->port, subj);
free(subj);
}
X509_free(cert);
break;
} else {
debug(DBG_ERR, "tlsconnect: certificate verification failed for %s (%s port %s)", server->conf->name, hp->host, hp->port);
}
X509_free(cert);
break;

concleanup:
/* ensure previous connection is properly closed */
cleanup_connection(server);
}
X509_free(cert);
if (server->ssl) break;
}
debug(DBG_WARN, "tlsconnect: TLS connection to %s up", server->conf->name);

origflags = fcntl(server->sock, F_GETFL, 0);
if (origflags == -1) {
Expand Down

0 comments on commit 86220e7

Please sign in to comment.