uhttpd: rework CyaSSL and OpenSSL integration; move protected recv() and send() opera...
authorJo-Philipp Wich <jow@openwrt.org>
Sat, 5 Nov 2011 03:19:07 +0000 (03:19 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sat, 5 Nov 2011 03:19:07 +0000 (03:19 +0000)
SVN-Revision: 28761

package/uhttpd/Makefile
package/uhttpd/src/Makefile
package/uhttpd/src/uhttpd-tls.c
package/uhttpd/src/uhttpd-utils.c
package/uhttpd/src/uhttpd-utils.h

index 4f292848836bc13d17ac4bfcde7b5ed5eab18951..daf7333cd65fa9a5212c09d1c5daf61ef023e174 100644 (file)
@@ -65,14 +65,16 @@ endef
 
 UHTTPD_TLS:=
 TLS_CFLAGS:=
+TLS_LDFLAGS:=
 
 ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_cyassl),)
   UHTTPD_TLS:=cyassl
-  TLS_CFLAGS:=-I$(STAGING_DIR)/usr/include/cyassl
+  TLS_CFLAGS:=-I$(STAGING_DIR)/usr/include/cyassl -DTLS_IS_CYASSL
 endif
 
 ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_openssl),)
   UHTTPD_TLS:=openssl
+  TLS_CFLAGS:=-DTLS_IS_OPENSSL
 endif
 
 
index e18833e8f3c2dcf416b4c5f54f89c879673bb06f..9c3cc7f02c1d823606f17f0906d10c878dca1689 100644 (file)
@@ -3,19 +3,17 @@ LUA_SUPPORT ?= 1
 TLS_SUPPORT ?= 1
 UHTTPD_TLS ?= cyassl
 
-CFLAGS ?= -I./lua-5.1.4/src -I$(TLS_INCLUDE_DIR) -O0 -ggdb3
-LDFLAGS ?= -L./lua-5.1.4/src -L$(TLS_LIB_DIR)
+CFLAGS ?= -I./lua-5.1.4/src $(TLS_CFLAGS) -O0 -ggdb3
+LDFLAGS ?= -L./lua-5.1.4/src $(TLS_LDFLAGS)
 
 CFLAGS += -Wall --std=gnu99
 
 ifeq ($(UHTTPD_TLS),openssl)
-  TLS_LDFLAGS := -lssl
-  TLS_INCLUDE_DIR := ./openssl-0.9.8m/include
-  TLS_LIB_DIR := ./openssl-0.9.8m
+  TLS_LDFLAGS := -L./openssl-0.9.8m -lssl
+  TLS_CFLAGS := -I./openssl-0.9.8m/include -DTLS_IS_OPENSSL
 else
-  TLS_LDFLAGS := -lcyassl
-  TLS_INCLUDE_DIR := ./cyassl-1.4.0/include
-  TLS_LIB_DIR := ./cyassl-1.4.0/src/.libs
+  TLS_LDFLAGS := -L./cyassl-1.4.0/src/.libs -lcyassl
+  TLS_CFLAGS := -I./cyassl-1.4.0/include -DTLS_IS_CYASSL
 endif
 
 OBJ := uhttpd.o uhttpd-file.o uhttpd-utils.o
@@ -31,15 +29,26 @@ ifeq ($(HAVE_SHADOW),yes)
   CFLAGS += -DHAVE_SHADOW
 endif
 
-world: compile
+ifeq ($(TLS_SUPPORT),1)
+  CFLAGS += -DHAVE_TLS
+endif
 
 ifeq ($(CGI_SUPPORT),1)
-  OBJ += uhttpd-cgi.o
   CFLAGS += -DHAVE_CGI
 endif
 
 ifeq ($(LUA_SUPPORT),1)
   CFLAGS += -DHAVE_LUA
+endif
+
+
+world: compile
+
+ifeq ($(CGI_SUPPORT),1)
+  OBJ += uhttpd-cgi.o
+endif
+
+ifeq ($(LUA_SUPPORT),1)
   LUALIB := uhttpd_lua.so
 
   $(LUALIB): uhttpd-lua.c
@@ -49,12 +58,11 @@ ifeq ($(LUA_SUPPORT),1)
 endif
 
 ifeq ($(TLS_SUPPORT),1)
-  CFLAGS += -DHAVE_TLS
   TLSLIB := uhttpd_tls.so
 
   $(TLSLIB): uhttpd-tls.c
                $(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
-                       -shared $(TLS_LDFLAGS) \
+                       -shared \
                        -o $(TLSLIB) uhttpd-tls.c
 endif
 
index 6beae25aa153c03c6973a655fd3d98c9e5f1f5fd..4a9e907922cab2b6460f883efeeb15643adf7be8 100644 (file)
 #include "uhttpd-tls.h"
 #include "uhttpd-utils.h"
 
+#include <syslog.h>
+#define dbg(...) syslog(LOG_INFO, __VA_ARGS__)
+
+#ifdef TLS_IS_CYASSL
+static int uh_cyassl_recv_cb(char *buf, int sz, void *ctx)
+{
+       int rv;
+       int socket = *(int *)ctx;
+       struct client *cl;
+
+       if (!(cl = uh_client_lookup(socket)))
+               return -1; /* unexpected error */
+
+       rv = uh_tcp_recv_lowlevel(cl, buf, sz);
+
+       if (rv < 0)
+               return -4; /* interrupted */
+
+       if (rv == 0)
+               return -5; /* connection closed */
+
+       return rv;
+}
+
+static int uh_cyassl_send_cb(char *buf, int sz, void *ctx)
+{
+       int rv;
+       int socket = *(int *)ctx;
+       struct client *cl;
+
+       if (!(cl = uh_client_lookup(socket)))
+               return -1; /* unexpected error */
+
+       rv = uh_tcp_send_lowlevel(cl, buf, sz);
+
+       if (rv <= 0)
+               return -5; /* connection dead */
+
+       return rv;
+}
+
+void SetCallbackIORecv_Ctx(SSL_CTX*, int (*)(char *, int, void *));
+void SetCallbackIOSend_Ctx(SSL_CTX*, int (*)(char *, int, void *));
+
+static void uh_tls_ctx_setup(SSL_CTX *ctx)
+{
+       SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+       SetCallbackIORecv_Ctx(ctx, uh_cyassl_recv_cb);
+       SetCallbackIOSend_Ctx(ctx, uh_cyassl_send_cb);
+       return;
+}
+
+static int uh_tls_client_ctx_setup(SSL *ssl, int socket)
+{
+       return SSL_set_fd(ssl, socket);
+}
+#endif /* TLS_IS_CYASSL */
+
+#ifdef TLS_IS_OPENSSL
+static long uh_openssl_bio_ctrl_cb(BIO *b, int cmd, long num, void *ptr)
+{
+       long rv = 1;
+
+       switch (cmd)
+       {
+               case BIO_C_SET_FD:
+                       b->num      = *((int *)ptr);
+                       b->shutdown = (int)num;
+                       b->init     = 1;
+                       break;
+
+               case BIO_C_GET_FD:
+                       if (!b->init)
+                               return -1;
+
+                       if (ptr)
+                               *((int *)ptr) = b->num;
+
+                       rv = b->num;
+                       break;
+       }
+
+       return rv;
+}
+
+static int uh_openssl_bio_read_cb(BIO *b, char *out, int outl)
+{
+       int rv = 0;
+       struct client *cl;
+
+       if (!(cl = uh_client_lookup(b->num)))
+               return -1;
+
+       if (out != NULL)
+               rv = uh_tcp_recv_lowlevel(cl, out, outl);
+
+       return rv;
+}
+
+static int uh_openssl_bio_write_cb(BIO *b, const char *in, int inl)
+{
+       struct client *cl;
+
+       if (!(cl = uh_client_lookup(b->num)))
+               return -1;
+
+       return uh_tcp_send_lowlevel(cl, in, inl);
+}
+
+static BIO_METHOD uh_openssl_bio_methods = {
+       .type   = BIO_TYPE_SOCKET,
+       .name   = "uhsocket",
+       .ctrl   = uh_openssl_bio_ctrl_cb,
+       .bwrite = uh_openssl_bio_write_cb,
+       .bread  = uh_openssl_bio_read_cb
+};
+
+static void uh_tls_ctx_setup(SSL_CTX *ctx)
+{
+       SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+       return;
+}
+
+static int uh_tls_client_ctx_setup(SSL *ssl, int socket)
+{
+       BIO *b;
+
+       if (!(b = BIO_new(&uh_openssl_bio_methods)))
+               return 0;
+
+       BIO_set_fd(b, socket, BIO_NOCLOSE);
+       SSL_set_bio(ssl, b, b);
+
+       return 1;
+}
+#endif /* TLS_IS_OPENSSL */
+
 
 SSL_CTX * uh_tls_ctx_init()
 {
@@ -28,8 +165,8 @@ SSL_CTX * uh_tls_ctx_init()
        SSL_load_error_strings();
        SSL_library_init();
 
-       if( (c = SSL_CTX_new(TLSv1_server_method())) != NULL )
-               SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
+       if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL)
+               uh_tls_ctx_setup(c);
 
        return c;
 }
@@ -69,8 +206,9 @@ int uh_tls_client_accept(struct client *c)
                c->tls = SSL_new(c->server->tls);
                if( c->tls )
                {
-                       if( (rv = SSL_set_fd(c->tls, c->socket)) < 1 )
+                       if( (rv = uh_tls_client_ctx_setup(c->tls, c->socket)) < 1 )
                                goto cleanup;
+
                        if( (rv = SSL_accept(c->tls)) < 1 )
                                goto cleanup;
                }
index ac00af824e7801e314b854c32940739a75a746e0..d48f6bcf11908bb160dded5fae374ea6c0275463 100644 (file)
@@ -124,7 +124,7 @@ int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t)
 }
 
 
-int uh_tcp_send(struct client *cl, const char *buf, int len)
+int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len)
 {
        fd_set writer;
        struct timeval timeout;
@@ -135,21 +135,28 @@ int uh_tcp_send(struct client *cl, const char *buf, int len)
        timeout.tv_sec = cl->server->conf->network_timeout;
        timeout.tv_usec = 0;
 
-       if( select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0 )
-       {
-#ifdef HAVE_TLS
-               if( cl->tls )
-                       return cl->server->conf->tls_send(cl, (void *)buf, len);
-               else
-#endif
-                       return send(cl->socket, buf, len, 0);
-       }
+       if (select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0)
+               return send(cl->socket, buf, len, 0);
 
        return -1;
 }
 
+int uh_tcp_send(struct client *cl, const char *buf, int len)
+{
+#ifdef HAVE_TLS
+       if (cl->tls)
+               return cl->server->conf->tls_send(cl, (void *)buf, len);
+       else
+#endif
+               return uh_tcp_send_lowlevel(cl, buf, len);
+}
+
 int uh_tcp_peek(struct client *cl, char *buf, int len)
 {
+       /* sanity check, prevent overflowing peek buffer */
+       if (len > sizeof(cl->peekbuf))
+               return -1;
+
        int sz = uh_tcp_recv(cl, buf, len);
 
        /* store received data in peek buffer */
@@ -162,49 +169,51 @@ int uh_tcp_peek(struct client *cl, char *buf, int len)
        return sz;
 }
 
+int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len)
+{
+       fd_set reader;
+       struct timeval timeout;
+
+       FD_ZERO(&reader);
+       FD_SET(cl->socket, &reader);
+
+       timeout.tv_sec  = cl->server->conf->network_timeout;
+       timeout.tv_usec = 0;
+
+       if (select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0)
+               return recv(cl->socket, buf, len, 0);
+
+       return -1;
+}
+
 int uh_tcp_recv(struct client *cl, char *buf, int len)
 {
        int sz = 0;
        int rsz = 0;
 
-       fd_set reader;
-       struct timeval timeout;
-
        /* first serve data from peek buffer */
-       if( cl->peeklen > 0 )
+       if (cl->peeklen > 0)
        {
                sz = min(cl->peeklen, len);
                len -= sz; cl->peeklen -= sz;
-
                memcpy(buf, cl->peekbuf, sz);
                memmove(cl->peekbuf, &cl->peekbuf[sz], cl->peeklen);
        }
 
        /* caller wants more */
-       if( len > 0 )
+       if (len > 0)
        {
-               FD_ZERO(&reader);
-               FD_SET(cl->socket, &reader);
-
-               timeout.tv_sec  = cl->server->conf->network_timeout;
-               timeout.tv_usec = 0;
-
-               if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 )
-               {
 #ifdef HAVE_TLS
-                       if( cl->tls )
-                               rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
-                       else
+               if (cl->tls)
+                       rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
+               else
 #endif
-                               rsz = recv(cl->socket, (void *)&buf[sz], len, 0);
+                       rsz = uh_tcp_recv_lowlevel(cl, (void *)&buf[sz], len);
 
-                       if( (sz == 0) || (rsz > 0) )
-                               sz += rsz;
-               }
-               else if( sz == 0 )
-               {
-                       sz = -1;
-               }
+               if (rsz < 0)
+                       return rsz;
+
+               sz += rsz;
        }
 
        return sz;
index 769e5b45d6137801f79ce4440e09e691f52d814c..a2cac35ac59eda8004128a6bba4364fb1e6ee62a 100644 (file)
@@ -67,8 +67,10 @@ char *strfind(char *haystack, int hslen, const char *needle, int ndlen);
 int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t);
 
 int uh_tcp_send(struct client *cl, const char *buf, int len);
+int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len);
 int uh_tcp_peek(struct client *cl, char *buf, int len);
 int uh_tcp_recv(struct client *cl, char *buf, int len);
+int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len);
 
 int uh_http_sendhf(
        struct client *cl, int code, const char *summary,