Commit a2a0f702 authored by venaas's avatar venaas Committed by venaas

made dtls server do proper certificate matching

git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@356 e88ac4ed-0b26-0410-9574-a7f39faa03bf
parent fbb9d82b
......@@ -28,6 +28,7 @@
#include <openssl/err.h>
#include "debug.h"
#include "list.h"
#include "hash.h"
#include "util.h"
#include "radsecproxy.h"
#include "dtls.h"
......@@ -96,12 +97,16 @@ void *udpdtlsserverrd(void *arg) {
unsigned char buf[4];
struct sockaddr_storage from;
socklen_t fromlen = sizeof(from);
struct clsrvconf *conf;
struct list_node *node;
struct client *client;
fd_set readfds;
pthread_t dtlsserverth;
struct hash *rbiosh;
struct queue *rbiosq;
rbiosh = hash_create();
if (!rbiosh)
debugx(1, DBG_ERR, "udpdtlsserverrd: malloc failed");
for (;;) {
FD_ZERO(&readfds);
FD_SET(s, &readfds);
......@@ -112,34 +117,36 @@ void *udpdtlsserverrd(void *arg) {
debug(DBG_WARN, "udpdtlsserverrd: recv failed");
continue;
}
conf = find_clconf(RAD_DTLS, (struct sockaddr *)&from, NULL);
if (!conf) {
debug(DBG_WARN, "udpdtlsserverrd: got packet from wrong or unknown DTLS peer %s, ignoring", addr2string((struct sockaddr *)&from, fromlen));
recv(s, buf, 4, 0);
rbiosq = hash_read(rbiosh, &from, fromlen);
if (rbiosq) {
if (udp2bio(s, rbiosq, cnt))
debug(DBG_DBG, "udpdtlsserverrd: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen));
continue;
}
node = list_first(conf->clients);
if (node)
client = (struct client *)node->data;
else {
client = addclient(conf);
if (!client) {
recv(s, buf, 4, 0);
continue;
}
client->sock = s;
memcpy(&client->addr, &from, fromlen);
if (pthread_create(&dtlsserverth, NULL, dtlsservernew, (void *)client)) {
debug(DBG_ERR, "udpdtlsserverrd: pthread_create failed");
removeclient(client);
recv(s, buf, 4, 0);
/* from new source, new client? */
client = malloc(sizeof(struct client));
if (!client)
continue;
client->rbios = rbiosq = newqueue();
if (!hash_insert(rbiosh, &from, fromlen, rbiosq)) {
free(client);
removequeue(rbiosq);
continue;
}
client->sock = s;
memcpy(&client->addr, &from, fromlen);
if (udp2bio(s, rbiosq, cnt)) {
debug(DBG_DBG, "udpdtlsserverrd: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen));
if (!pthread_create(&dtlsserverth, NULL, dtlsservernew, (void *)client)) {
pthread_detach(dtlsserverth);
continue;
}
pthread_detach(dtlsserverth);
debug(DBG_ERR, "udpdtlsserverrd: pthread_create failed");
}
if (udp2bio(s, client->rbios, cnt))
debug(DBG_DBG, "udpdtlsserverrd: got DTLS in UDP from %s", addr2string((struct sockaddr *)&from, fromlen));
free(client);
freebios(hash_extract(rbiosh, &from, fromlen));
}
}
......@@ -323,26 +330,56 @@ SSL *dtlsacccon(uint8_t acc, SSL_CTX *ctx, int s, struct sockaddr *addr, struct
}
void *dtlsservernew(void *arg) {
struct client *client = (struct client *)arg;
struct client *client, *clpar = (struct client *)arg;
struct clsrvconf *conf;
struct list_node *cur = NULL;
int s;
SSL *ssl = NULL;
X509 *cert = NULL;
struct queue *rbios;
struct sockaddr_storage addr;
s = clpar->sock;
rbios = clpar->rbios;
addr = clpar->addr;
free(clpar);
conf = find_clconf(RAD_DTLS, (struct sockaddr *)&addr, NULL);
if (conf) {
ssl = dtlsacccon(1, conf->ssl_ctx, s, (struct sockaddr *)&addr, rbios);
if (!ssl)
goto exit;
cert = verifytlscert(ssl);
if (!cert)
goto exit;
}
while (conf) {
if (verifyconfcert(cert, conf)) {
X509_free(cert);
client = addclient(conf);
if (client) {
client->sock = s;
client->rbios = rbios;
client->addr = addr;
client->ssl = ssl;
dtlsserverrd(client);
removeclient(client);
} else {
debug(DBG_WARN, "dtlsservernew: failed to create new client instance");
}
goto exit;
}
conf = find_clconf(RAD_DTLS, (struct sockaddr *)&client->addr, &cur);
}
debug(DBG_WARN, "dtlsservernew: ignoring request, no matching TLS client");
client->ssl = dtlsacccon(1, client->conf->ssl_ctx, client->sock, (struct sockaddr *)&client->addr, client->rbios);
if (!client->ssl)
goto exit;
cert = verifytlscert(client->ssl);
if (!cert)
goto exit;
if (verifyconfcert(cert, client->conf)) {
X509_free(cert);
dtlsserverrd(client);
removeclient(client);
} else
debug(DBG_WARN, "dtlsservernew: ignoring request, certificate validation failed");
if (cert)
X509_free(cert);
exit:
SSL_free(client->ssl);
/* mark rbios for removal, to be removed by udpdtlsserverrd()*/
SSL_free(ssl);
ERR_remove_state(0);
pthread_exit(NULL);
}
......@@ -474,11 +511,6 @@ void *dtlsclientrd(void *arg) {
}
}
void addclientdtls(struct client *client) {
client->replyq = newqueue();
client->rbios = newqueue();
}
void addserverextradtls(struct clsrvconf *conf) {
switch (conf->addrinfo->ai_family) {
case AF_INET:
......
......@@ -12,6 +12,5 @@ void *dtlsservernew(void *arg);
void *dtlsclientrd(void *arg);
void *udpdtlsclientrd(void *arg);
int clientradputdtls(struct server *server, unsigned char *rad);
void addclientdtls(struct client *client);
void addserverextradtls(struct clsrvconf *conf);
void initextradtls();
......@@ -92,3 +92,25 @@ void *hash_read(struct hash *h, void *key, uint32_t keylen) {
pthread_mutex_unlock(&h->mutex);
return NULL;
}
/* extracts entry from hash */
void *hash_extract(struct hash *h, void *key, uint32_t keylen) {
struct list_node *ln;
struct entry *e;
if (!h)
return 0;
pthread_mutex_lock(&h->mutex);
for (ln = list_first(h->hashlist); ln; ln = list_next(ln)) {
e = (struct entry *)ln->data;
if (e->keylen == keylen && !memcmp(e->key, key, keylen)) {
free(e->key);
list_removedata(h->hashlist, e);
free(e);
pthread_mutex_unlock(&h->mutex);
return e->data;
}
}
pthread_mutex_unlock(&h->mutex);
return NULL;
}
......@@ -24,3 +24,6 @@ int hash_insert(struct hash *hash, void *key, uint32_t keylen, void *data);
/* reads entry from hash */
void *hash_read(struct hash *hash, void *key, uint32_t keylen);
/* extracts (read and remove) entry from hash */
void *hash_extract(struct hash *hash, void *key, uint32_t keylen);
......@@ -155,7 +155,7 @@ static const struct protodefs protodefs[] = {
dtlsconnect, /* connecter */
dtlsclientrd, /* clientconnreader */
clientradputdtls, /* clientradput */
addclientdtls, /* addclient */
NULL, /* addclient */
addserverextradtls, /* addserverextra */
initextradtls /* initextra */
},
......@@ -528,7 +528,9 @@ struct queue *newqueue() {
void removequeue(struct queue *q) {
struct list_node *entry;
if (!q)
return;
pthread_mutex_lock(&q->mutex);
for (entry = list_first(q->entries); entry; entry = list_next(entry))
free(((struct reply *)entry)->buf);
......@@ -536,6 +538,7 @@ void removequeue(struct queue *q) {
pthread_cond_destroy(&q->cond);
pthread_mutex_unlock(&q->mutex);
pthread_mutex_destroy(&q->mutex);
free(q);
}
void freebios(struct queue *q) {
......@@ -577,8 +580,6 @@ void removeclient(struct client *client) {
if (!client || !client->conf->clients)
return;
removequeue(client->replyq);
if (client->rbios)
freebios(client->rbios);
list_removedata(client->conf->clients, client);
free(client);
}
......
......@@ -208,6 +208,8 @@ struct client *addclient(struct clsrvconf *conf);
void removeclient(struct client *client);
void removeclientrqs(struct client *client);
struct queue *newqueue();
void removequeue(struct queue *q);
void freebios(struct queue *q);
int radsrv(struct request *rq);
X509 *verifytlscert(SSL *ssl);
int verifyconfcert(X509 *cert, struct clsrvconf *conf);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment