aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2011-11-05 03:19:07 +0000
committerJo-Philipp Wich <jow@openwrt.org>2011-11-05 03:19:07 +0000
commit3d035a6f6ab63c2e3031678cda194435526da918 (patch)
tree4ce7c6471e317efce3baa1419d53f2b948637740
parent297ac9a7f1a7c01521d834e07c44a45620257069 (diff)
downloadupstream-3d035a6f6ab63c2e3031678cda194435526da918.tar.gz
upstream-3d035a6f6ab63c2e3031678cda194435526da918.tar.bz2
upstream-3d035a6f6ab63c2e3031678cda194435526da918.zip
uhttpd: rework CyaSSL and OpenSSL integration; move protected recv() and send() operations below the ssl layer - fixes hangs when accessing via https
SVN-Revision: 28761
-rw-r--r--package/uhttpd/Makefile4
-rw-r--r--package/uhttpd/src/Makefile32
-rw-r--r--package/uhttpd/src/uhttpd-tls.c144
-rw-r--r--package/uhttpd/src/uhttpd-utils.c79
-rw-r--r--package/uhttpd/src/uhttpd-utils.h2
5 files changed, 210 insertions, 51 deletions
diff --git a/package/uhttpd/Makefile b/package/uhttpd/Makefile
index 4f29284883..daf7333cd6 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 e18833e8f3..9c3cc7f02c 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 6beae25aa1..4a9e907922 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 ac00af824e..d48f6bcf11 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 769e5b45d6..a2cac35ac5 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,