From 0e9f9a724693e5be0fd620cf3e971db7098436e3 Mon Sep 17 00:00:00 2001 From: venaas Date: Thu, 17 Apr 2008 11:25:26 +0000 Subject: restructuring of tls server code git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@238 e88ac4ed-0b26-0410-9574-a7f39faa03bf --- radsecproxy.c | 206 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 125 insertions(+), 81 deletions(-) diff --git a/radsecproxy.c b/radsecproxy.c index 130f3aa..9f49a19 100644 --- a/radsecproxy.c +++ b/radsecproxy.c @@ -744,26 +744,28 @@ int subjectaltnameregexp(X509 *cert, int type, char *exact, regex_t *regex) { return r; } -int tlsverifycert(SSL *ssl, struct clsrvconf *conf) { - int r; +X509 *verifytlscert(SSL *ssl) { X509 *cert; - uint8_t type = 0; /* 0 for DNS, AF_INET for IPv4, AF_INET6 for IPv6 */ unsigned long error; - struct in6_addr addr; if (SSL_get_verify_result(ssl) != X509_V_OK) { - debug(DBG_ERR, "tlsverifycert: basic validation failed"); + debug(DBG_ERR, "verifytlscert: basic validation failed"); while ((error = ERR_get_error())) - debug(DBG_ERR, "tlsverifycert: TLS: %s", ERR_error_string(error, NULL)); - return 0; + debug(DBG_ERR, "verifytlscert: TLS: %s", ERR_error_string(error, NULL)); + return NULL; } cert = SSL_get_peer_certificate(ssl); - if (!cert) { - debug(DBG_ERR, "tlsverifycert: failed to obtain certificate"); - return 0; - } - + if (!cert) + debug(DBG_ERR, "verifytlscert: failed to obtain certificate"); + return cert; +} + +int verifyconfcert(X509 *cert, struct clsrvconf *conf) { + int r; + uint8_t type = 0; /* 0 for DNS, AF_INET for IPv4, AF_INET6 for IPv6 */ + struct in6_addr addr; + if (conf->prefixlen == 255) { if (inet_pton(AF_INET, conf->host, &addr)) type = AF_INET; @@ -773,44 +775,40 @@ int tlsverifycert(SSL *ssl, struct clsrvconf *conf) { r = type ? subjectaltnameaddr(cert, type, &addr) : subjectaltnameregexp(cert, GEN_DNS, conf->host, NULL); if (r) { if (r < 0) { - debug(DBG_DBG, "tlsverifycert: No subjectaltname matching %s %s", type ? "address" : "host", conf->host); - goto errexit; + debug(DBG_DBG, "verifyconfcert: No subjectaltname matching %s %s", type ? "address" : "host", conf->host); + return 0; } - debug(DBG_DBG, "tlsverifycert: Found subjectaltname matching %s %s", type ? "address" : "host", conf->host); + debug(DBG_DBG, "verifyconfcert: Found subjectaltname matching %s %s", type ? "address" : "host", conf->host); } else { if (!cnregexp(cert, conf->host, NULL)) { - debug(DBG_ERR, "tlsverifycert: cn not matching host %s", conf->host); - goto errexit; + debug(DBG_ERR, "verifyconfcert: cn not matching host %s", conf->host); + return 0; } - debug(DBG_DBG, "tlsverifycert: Found cn matching host %s", conf->host); + debug(DBG_DBG, "verifyconfcert: Found cn matching host %s", conf->host); } } if (conf->certcnregex) { if (cnregexp(cert, NULL, conf->certcnregex) < 1) { - debug(DBG_DBG, "tlsverifycert: CN not matching regex"); - goto errexit; + debug(DBG_DBG, "verifyconfcert: CN not matching regex"); + return 0; } - debug(DBG_DBG, "tlsverifycert: CN matching regex"); + debug(DBG_DBG, "verifyconfcert: CN matching regex"); } if (conf->certuriregex) { if (subjectaltnameregexp(cert, GEN_URI, NULL, conf->certuriregex) < 1) { - debug(DBG_DBG, "tlsverifycert: subjectaltname URI not matching regex"); - goto errexit; + debug(DBG_DBG, "verifyconfcert: subjectaltname URI not matching regex"); + return 0; } - debug(DBG_DBG, "tlsverifycert: subjectaltname URI matching regex"); + debug(DBG_DBG, "verifyconfcert: subjectaltname URI matching regex"); } - X509_free(cert); return 1; - - errexit: - X509_free(cert); - return 0; } void tlsconnect(struct server *server, struct timeval *when, char *text) { struct timeval now; time_t elapsed; - + X509 *cert; + debug(DBG_DBG, "tlsconnect called from %s", text); pthread_mutex_lock(&server->lock); if (when && memcmp(&server->lastconnecttry, when, sizeof(struct timeval))) { @@ -849,8 +847,16 @@ void tlsconnect(struct server *server, struct timeval *when, char *text) { SSL_free(server->ssl); server->ssl = SSL_new(server->conf->ssl_ctx); SSL_set_fd(server->ssl, server->sock); - if (SSL_connect(server->ssl) > 0 && tlsverifycert(server->ssl, server->conf)) + if (SSL_connect(server->ssl) <= 0) + continue; + cert = verifytlscert(server->ssl); + if (!cert) + continue; + if (verifyconfcert(cert, server->conf)) { + X509_free(cert); break; + } + X509_free(cert); } debug(DBG_WARN, "tlsconnect: TLS connection to %s port %s up", server->conf->host, server->conf->port); gettimeofday(&server->lastconnecttry, NULL); @@ -2299,95 +2305,133 @@ void *tlsserverwr(void *arg) { } } -void *tlsserverrd(void *arg) { +void tlsserverrd(struct client *client) { struct request rq; + pthread_t tlsserverwrth; + + debug(DBG_DBG, "tlsserverrd starting for %s", client->conf->host); + + if (pthread_create(&tlsserverwrth, NULL, tlsserverwr, (void *)client)) { + debug(DBG_ERR, "tlsserverrd: pthread_create failed"); + return; + } + + for (;;) { + memset(&rq, 0, sizeof(struct request)); + rq.buf = radtlsget(client->ssl); + if (!rq.buf) + break; + debug(DBG_DBG, "tlsserverrd: got Radius message from %s", client->conf->host); + rq.from = client; + radsrv(&rq); + } + + debug(DBG_ERR, "tlsserverrd: connection lost"); + /* stop writer by setting ssl to NULL and give signal in case waiting for data */ + client->ssl = NULL; + pthread_mutex_lock(&client->replyq->mutex); + pthread_cond_signal(&client->replyq->cond); + pthread_mutex_unlock(&client->replyq->mutex); + debug(DBG_DBG, "tlsserverrd: waiting for writer to end"); + pthread_join(tlsserverwrth, NULL); + removeclientrqs(client); + debug(DBG_DBG, "tlsserverrd for %s exiting", client->conf->host); +} + +void *tlsservernew(void *arg) { unsigned long error; int s; struct client *client = (struct client *)arg; - pthread_t tlsserverwrth; SSL *ssl; + X509 *cert; - debug(DBG_DBG, "tlsserverrd starting for %s", client->conf->host); + debug(DBG_DBG, "tlsservernew starting for %s", client->conf->host); ssl = client->ssl; if (SSL_accept(ssl) <= 0) { while ((error = ERR_get_error())) - debug(DBG_ERR, "tlsserverrd: SSL: %s", ERR_error_string(error, NULL)); + debug(DBG_ERR, "tlsservernew: SSL: %s", ERR_error_string(error, NULL)); debug(DBG_ERR, "SSL_accept failed"); - goto errexit; + goto exit; } - if (tlsverifycert(client->ssl, client->conf)) { - if (pthread_create(&tlsserverwrth, NULL, tlsserverwr, (void *)client)) { - debug(DBG_ERR, "tlsserverrd: pthread_create failed"); - goto errexit; - } - for (;;) { - memset(&rq, 0, sizeof(struct request)); - rq.buf = radtlsget(client->ssl); - if (!rq.buf) - break; - debug(DBG_DBG, "tlsserverrd: got Radius message from %s", client->conf->host); - rq.from = client; - radsrv(&rq); - } - debug(DBG_ERR, "tlsserverrd: connection lost"); - /* stop writer by setting ssl to NULL and give signal in case waiting for data */ - client->ssl = NULL; - pthread_mutex_lock(&client->replyq->mutex); - pthread_cond_signal(&client->replyq->cond); - pthread_mutex_unlock(&client->replyq->mutex); - debug(DBG_DBG, "tlsserverrd: waiting for writer to end"); - pthread_join(tlsserverwrth, NULL); + + cert = verifytlscert(ssl); + if (!cert) + goto exit; + if (!verifyconfcert(cert, client->conf)) { + X509_free(cert); + goto exit; } + X509_free(cert); + tlsserverrd(client); - errexit: + exit: s = SSL_get_fd(ssl); SSL_free(ssl); shutdown(s, SHUT_RDWR); close(s); - debug(DBG_DBG, "tlsserverrd thread for %s exiting", client->conf->host); - removeclientrqs(client); removeclient(client); + debug(DBG_DBG, "tlsservernew thread for %s exiting", client->conf->host); pthread_exit(NULL); } /*********************************************** - * new tls listening code + * new tls server code ***********************************************/ -void *tlsserverrd2(void *arg) { +void *tlsservernew2(void *arg) { int s; struct sockaddr_storage from; size_t fromlen = sizeof(from); struct clsrvconf *conf; struct list_node *cur = NULL; SSL *ssl = NULL; + X509 *cert = NULL; + unsigned long error; struct client *client; s = *(int *)arg; if (getpeername(s, (struct sockaddr *)&from, &fromlen)) { debug(DBG_DBG, "tlsserverrd: getpeername failed, exiting"); - goto errexit; + goto exit; } debug(DBG_WARN, "incoming TLS connection from %s", addr2string((struct sockaddr *)&from, fromlen)); - while ((conf = find_conf('T', (struct sockaddr *)&from, clconfs, &cur))) { - if (!ssl) { - ssl = SSL_new(conf->ssl_ctx); - SSL_set_fd(ssl, s); + + conf = find_conf('T', (struct sockaddr *)&from, clconfs, &cur); + if (conf) { + ssl = SSL_new(conf->ssl_ctx); + SSL_set_fd(ssl, s); + + if (SSL_accept(ssl) <= 0) { + while ((error = ERR_get_error())) + debug(DBG_ERR, "tlsserverrd: SSL: %s", ERR_error_string(error, NULL)); + debug(DBG_ERR, "SSL_accept failed"); + goto exit; } - client = addclient(conf); - if (!client) { - debug(DBG_WARN, "Failed to create new client instance"); - goto errexit; + cert = verifytlscert(ssl); + if (!cert) + goto exit; + } + + while (conf) { + if (verifyconfcert(cert, conf)) { + X509_free(cert); + client = addclient(conf); + if (client) { + client->ssl = ssl; + tlsserverrd(client); + removeclient(client); + } else + debug(DBG_WARN, "Failed to create new client instance"); + goto exit; } - /* todo */ - client->ssl = ssl; - /* todo */ + conf = find_conf('T', (struct sockaddr *)&from, clconfs, &cur); } debug(DBG_WARN, "ignoring request, no matching TLS client"); + if (cert) + X509_free(cert); - errexit: - if (ssl) - SSL_free(ssl); + exit: + SSL_free(ssl); shutdown(s, SHUT_RDWR); close(s); pthread_exit(NULL); @@ -2414,7 +2458,7 @@ int tlslistener2() { debug(DBG_WARN, "accept failed"); continue; } - if (pthread_create(&tlsserverth, NULL, tlsserverrd2, (void *)&snew)) { + if (pthread_create(&tlsserverth, NULL, tlsservernew, (void *)&snew)) { debug(DBG_ERR, "tlslistener: pthread_create failed"); shutdown(snew, SHUT_RDWR); close(snew); @@ -2463,16 +2507,16 @@ int tlslistener() { } client = addclient(conf); - if (!client) { debug(DBG_WARN, "Failed to create new client instance"); shutdown(snew, SHUT_RDWR); close(snew); continue; } + client->ssl = SSL_new(client->conf->ssl_ctx); SSL_set_fd(client->ssl, snew); - if (pthread_create(&tlsserverth, NULL, tlsserverrd, (void *)client)) { + if (pthread_create(&tlsserverth, NULL, tlsservernew, (void *)client)) { debug(DBG_ERR, "tlslistener: pthread_create failed"); SSL_free(client->ssl); removeclient(client); -- cgit v1.1