diff --git a/package/uhttpd/Makefile b/package/uhttpd/Makefile
index 4f292848836..daf7333cd65 100644
--- a/package/uhttpd/Makefile
+++ b/package/uhttpd/Makefile
@@ -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
 
 
diff --git a/package/uhttpd/src/Makefile b/package/uhttpd/src/Makefile
index e18833e8f3c..9c3cc7f02c1 100644
--- a/package/uhttpd/src/Makefile
+++ b/package/uhttpd/src/Makefile
@@ -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
 
diff --git a/package/uhttpd/src/uhttpd-tls.c b/package/uhttpd/src/uhttpd-tls.c
index 6beae25aa15..4a9e907922c 100644
--- a/package/uhttpd/src/uhttpd-tls.c
+++ b/package/uhttpd/src/uhttpd-tls.c
@@ -20,6 +20,143 @@
 #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;
 		}
diff --git a/package/uhttpd/src/uhttpd-utils.c b/package/uhttpd/src/uhttpd-utils.c
index ac00af824e7..d48f6bcf119 100644
--- a/package/uhttpd/src/uhttpd-utils.c
+++ b/package/uhttpd/src/uhttpd-utils.c
@@ -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;
diff --git a/package/uhttpd/src/uhttpd-utils.h b/package/uhttpd/src/uhttpd-utils.h
index 769e5b45d61..a2cac35ac59 100644
--- a/package/uhttpd/src/uhttpd-utils.h
+++ b/package/uhttpd/src/uhttpd-utils.h
@@ -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,