made dtls server do proper certificate matching
authorvenaas <venaas>
Thu, 21 Aug 2008 14:33:11 +0000 (14:33 +0000)
committervenaas <venaas@e88ac4ed-0b26-0410-9574-a7f39faa03bf>
Thu, 21 Aug 2008 14:33:11 +0000 (14:33 +0000)
git-svn-id: https://svn.testnett.uninett.no/radsecproxy/trunk@356 e88ac4ed-0b26-0410-9574-a7f39faa03bf

dtls.c
dtls.h
hash.c
hash.h
radsecproxy.c
radsecproxy.h

diff --git a/dtls.c b/dtls.c
index 9f68133..e872dd3 100644 (file)
--- a/dtls.c
+++ b/dtls.c
@@ -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:
diff --git a/dtls.h b/dtls.h
index af9054d..3005e18 100644 (file)
--- a/dtls.h
+++ b/dtls.h
@@ -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();
diff --git a/hash.c b/hash.c
index ea36860..dd27f77 100644 (file)
--- a/hash.c
+++ b/hash.c
@@ -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;
+}
diff --git a/hash.h b/hash.h
index f9268ea..dbf9543 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -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);
index c97e7ed..50bdd20 100644 (file)
@@ -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);
 }
index 2546470..e9f3bed 100644 (file)
@@ -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);