summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2014-08-04 17:38:13 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2014-08-04 17:38:13 +0000
commit5cf4c183bbfd2085dff5dc0908d4192bc7edf179 (patch)
tree4d0294cd57b66a7a0ac3678d058248f9090a1ea1 /usr.sbin
parent66412291b5910a4571d9e99f30d6d31bd8556817 (diff)
Proxy commit for jsing@:
"Add TLS/SSL support to httpd, based on the recent ressl commits." From jsing@ ok reyk@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/httpd/Makefile6
-rw-r--r--usr.sbin/httpd/config.c5
-rw-r--r--usr.sbin/httpd/httpd.conf.54
-rw-r--r--usr.sbin/httpd/httpd.h10
-rw-r--r--usr.sbin/httpd/parse.y17
-rw-r--r--usr.sbin/httpd/server.c228
6 files changed, 251 insertions, 19 deletions
diff --git a/usr.sbin/httpd/Makefile b/usr.sbin/httpd/Makefile
index 13f6e60c4e0..63d50f420b3 100644
--- a/usr.sbin/httpd/Makefile
+++ b/usr.sbin/httpd/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.24 2014/08/04 15:49:28 reyk Exp $
+# $OpenBSD: Makefile,v 1.25 2014/08/04 17:38:12 reyk Exp $
PROG= httpd
SRCS= parse.y
@@ -6,8 +6,8 @@ SRCS+= config.c control.c httpd.c log.c logger.c proc.c
SRCS+= server.c server_http.c server_file.c server_fcgi.c
MAN= httpd.8 httpd.conf.5
-LDADD= -levent -lutil
-DPADD= ${LIBEVENT} ${LIBUTIL}
+LDADD= -levent -lressl -lssl -lcrypto -lutil
+DPADD= ${LIBEVENT} ${LIBRESSL} ${LIBSSL} ${LIBCRYPTO} ${LIBUTIL}
#DEBUG= -g -DDEBUG=3
CFLAGS+= -Wall -I${.CURDIR}
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
diff --git a/usr.sbin/httpd/config.c b/usr.sbin/httpd/config.c
index c8e8af48c52..35405b8499b 100644
--- a/usr.sbin/httpd/config.c
+++ b/usr.sbin/httpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.14 2014/08/04 15:49:28 reyk Exp $ */
+/* $OpenBSD: config.c,v 1.15 2014/08/04 17:38:12 reyk Exp $ */
/*
* Copyright (c) 2011 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -305,8 +305,7 @@ config_getserver(struct httpd *env, struct imsg *imsg)
/* Add "host" to existing listening server */
if (imsg->fd != -1)
close(imsg->fd);
- return (config_getserver_config(env,
- srv, imsg));
+ return (config_getserver_config(env, srv, imsg));
}
if (srv_conf.flags & SRVFLAG_LOCATION)
diff --git a/usr.sbin/httpd/httpd.conf.5 b/usr.sbin/httpd/httpd.conf.5
index c04ddd1ed78..f25136e1332 100644
--- a/usr.sbin/httpd/httpd.conf.5
+++ b/usr.sbin/httpd/httpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: httpd.conf.5,v 1.20 2014/08/04 17:12:44 reyk Exp $
+.\" $OpenBSD: httpd.conf.5,v 1.21 2014/08/04 17:38:12 reyk Exp $
.\"
.\" Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
.\"
@@ -133,7 +133,7 @@ root directory of
.Nm httpd
and defaults to
.Pa /run/slowcgi.sock .
-.It Ic listen on Ar address Ic port Ar number
+.It Ic listen on Ar address Ic port Ar number Op Ic ssl
Set the listen address and port.
.It Ic location Ar path { ... }
Specify server configuration rules for a specific location.
diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h
index afd759a8317..9a7ef8b823f 100644
--- a/usr.sbin/httpd/httpd.h
+++ b/usr.sbin/httpd/httpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.h,v 1.40 2014/08/04 15:49:28 reyk Exp $ */
+/* $OpenBSD: httpd.h,v 1.41 2014/08/04 17:38:12 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -26,6 +26,7 @@
#include <sys/param.h> /* MAXHOSTNAMELEN */
#include <limits.h>
#include <imsg.h>
+#include <ressl.h>
#define CONF_FILE "/etc/httpd.conf"
#define HTTPD_SOCKET "/var/run/httpd.sock"
@@ -262,11 +263,14 @@ struct client {
in_port_t clt_port;
struct sockaddr_storage clt_ss;
struct bufferevent *clt_bev;
+ char *clt_buf;
+ size_t clt_buflen;
struct evbuffer *clt_output;
struct event clt_ev;
void *clt_desc;
int clt_fd;
+ struct ressl *clt_ressl_ctx;
struct bufferevent *clt_srvbev;
off_t clt_toread;
@@ -305,6 +309,7 @@ SPLAY_HEAD(client_tree, client);
#define SRVFLAG_SOCKET 0x0400
#define SRVFLAG_SYSLOG 0x0800
#define SRVFLAG_NO_SYSLOG 0x1000
+#define SRVFLAG_SSL 0x2000
#define SRVFLAG_BITS \
"\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX" \
@@ -366,6 +371,9 @@ struct server {
struct event srv_ev;
struct event srv_evt;
+ struct ressl *srv_ressl_ctx;
+ struct ressl_config *srv_ressl_config;
+
struct client_tree srv_clients;
};
TAILQ_HEAD(serverlist, server);
diff --git a/usr.sbin/httpd/parse.y b/usr.sbin/httpd/parse.y
index 7c42e47a421..649bd977981 100644
--- a/usr.sbin/httpd/parse.y
+++ b/usr.sbin/httpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.22 2014/08/04 16:07:59 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.23 2014/08/04 17:38:12 reyk Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -125,11 +125,13 @@ typedef struct {
%}
%token AUTO COMMON COMBINED CONNECTION DIRECTORY FCGI FILE INDEX LISTEN
-%token LOCATION LOG NO ON PORT PREFORK ROOT SERVER SOCKET STYLE SYSLOG TYPES
+%token LOCATION LOG NO ON PORT PREFORK ROOT SERVER SOCKET SSL STYLE SYSLOG
+%token TYPES
%token ERROR INCLUDE
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.port> port
+%type <v.number> optssl
%%
@@ -166,6 +168,10 @@ varset : STRING '=' STRING {
}
;
+optssl : /*empty*/ { $$ = 0; }
+ | SSL { $$ = 1; }
+ ;
+
main : PREFORK NUMBER {
if (loadcfg)
break;
@@ -240,7 +246,7 @@ serveropts_l : serveropts_l serveroptsl nl
| serveroptsl optnl
;
-serveroptsl : LISTEN ON STRING port {
+serveroptsl : LISTEN ON STRING port optssl {
struct addresslist al;
struct address *h;
struct server *s;
@@ -276,6 +282,10 @@ serveroptsl : LISTEN ON STRING port {
s->srv_conf.port = h->port.val[0];
s->srv_conf.prefixlen = h->prefixlen;
host_free(&al);
+
+ if ($5) {
+ s->srv_conf.flags |= SRVFLAG_SSL;
+ }
}
| ROOT STRING {
if (strlcpy(srv->srv_conf.root, $2,
@@ -620,6 +630,7 @@ lookup(char *s)
{ "root", ROOT },
{ "server", SERVER },
{ "socket", SOCKET },
+ { "ssl", SSL },
{ "style", STYLE },
{ "syslog", SYSLOG },
{ "types", TYPES }
diff --git a/usr.sbin/httpd/server.c b/usr.sbin/httpd/server.c
index 84f586fbfac..5748a85fefc 100644
--- a/usr.sbin/httpd/server.c
+++ b/usr.sbin/httpd/server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server.c,v 1.26 2014/08/04 15:49:28 reyk Exp $ */
+/* $OpenBSD: server.c,v 1.27 2014/08/04 17:38:12 reyk Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -42,6 +42,7 @@
#include <pwd.h>
#include <event.h>
#include <fnmatch.h>
+#include <ressl.h>
#include "httpd.h"
@@ -58,7 +59,12 @@ int server_socket(struct sockaddr_storage *, in_port_t,
int server_socket_listen(struct sockaddr_storage *, in_port_t,
struct server_config *);
+int server_ssl_init(struct server *);
+void server_ssl_readcb(int, short, void *);
+void server_ssl_writecb(int, short, void *);
+
void server_accept(int, short, void *);
+void server_accept_ssl(int, short, void *);
void server_input(struct client *);
extern void bufferevent_read_pressure_cb(struct evbuffer *, size_t,
@@ -108,6 +114,40 @@ server_privinit(struct server *srv)
return (0);
}
+int
+server_ssl_init(struct server *srv)
+{
+ if ((srv->srv_conf.flags & SRVFLAG_SSL) == 0)
+ return (0);
+
+ log_debug("%s: setting up SSL for %s", __func__, srv->srv_conf.name);
+
+ if (ressl_init() != 0) {
+ log_warn("%s: failed to initialise ressl", __func__);
+ return (-1);
+ }
+ if ((srv->srv_ressl_config = ressl_config_new()) == NULL) {
+ log_warn("%s: failed to get ressl config", __func__);
+ return (-1);
+ }
+ if ((srv->srv_ressl_ctx = ressl_server()) == NULL) {
+ log_warn("%s: failed to get ressl server", __func__);
+ return (-1);
+ }
+
+ /* XXX - make these configurable. */
+ ressl_config_set_cert_file(srv->srv_ressl_config, "/server.crt");
+ ressl_config_set_key_file(srv->srv_ressl_config, "/server.key");
+
+ if (ressl_configure(srv->srv_ressl_ctx, srv->srv_ressl_config) != 0) {
+ log_warn("%s: failed to configure SSL - %s", __func__,
+ ressl_error(srv->srv_ressl_ctx));
+ return (-1);
+ }
+
+ return (0);
+}
+
void
server_init(struct privsep *ps, struct privsep_proc *p, void *arg)
{
@@ -139,6 +179,7 @@ server_launch(void)
struct server *srv;
TAILQ_FOREACH(srv, env->sc_servers, srv_entry) {
+ server_ssl_init(srv);
server_http_init(srv);
log_debug("%s: running server %s", __func__,
@@ -181,6 +222,9 @@ server_purge(struct server *srv)
free(srv_conf);
}
+ ressl_config_free(srv->srv_ressl_config);
+ ressl_free(srv->srv_ressl_ctx);
+
free(srv);
}
@@ -364,6 +408,124 @@ server_socket_connect(struct sockaddr_storage *ss, in_port_t port,
}
void
+server_ssl_readcb(int fd, short event, void *arg)
+{
+ struct bufferevent *bufev = arg;
+ struct client *clt = bufev->cbarg;
+ char rbuf[IBUF_READ_SIZE];
+ int what = EVBUFFER_READ;
+ int howmuch = IBUF_READ_SIZE;
+ int ret;
+ size_t len;
+
+ if (event == EV_TIMEOUT) {
+ what |= EVBUFFER_TIMEOUT;
+ goto err;
+ }
+
+ if (bufev->wm_read.high != 0)
+ howmuch = MIN(sizeof(rbuf), bufev->wm_read.high);
+
+ ret = ressl_read(clt->clt_ressl_ctx, rbuf, howmuch, &len);
+ if (ret == RESSL_READ_AGAIN || ret == RESSL_WRITE_AGAIN) {
+ goto retry;
+ } else if (ret != 0) {
+ what |= EVBUFFER_ERROR;
+ goto err;
+ }
+
+ if (evbuffer_add(bufev->input, rbuf, len) == -1) {
+ what |= EVBUFFER_ERROR;
+ goto err;
+ }
+
+ server_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+
+ len = EVBUFFER_LENGTH(bufev->input);
+ if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
+ return;
+ if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) {
+ struct evbuffer *buf = bufev->input;
+ event_del(&bufev->ev_read);
+ evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
+ return;
+ }
+
+ if (bufev->readcb != NULL)
+ (*bufev->readcb)(bufev, bufev->cbarg);
+ return;
+
+retry:
+ server_bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+ return;
+
+err:
+ (*bufev->errorcb)(bufev, what, bufev->cbarg);
+}
+
+void
+server_ssl_writecb(int fd, short event, void *arg)
+{
+ struct bufferevent *bufev = arg;
+ struct client *clt = bufev->cbarg;
+ int ret;
+ short what = EVBUFFER_WRITE;
+ size_t len;
+
+ if (event == EV_TIMEOUT) {
+ what |= EVBUFFER_TIMEOUT;
+ goto err;
+ }
+
+ if (EVBUFFER_LENGTH(bufev->output)) {
+ if (clt->clt_buf == NULL) {
+ clt->clt_buflen = EVBUFFER_LENGTH(bufev->output);
+ if ((clt->clt_buf = malloc(clt->clt_buflen)) == NULL) {
+ what |= EVBUFFER_ERROR;
+ goto err;
+ }
+ bcopy(EVBUFFER_DATA(bufev->output),
+ clt->clt_buf, clt->clt_buflen);
+ }
+ ret = ressl_write(clt->clt_ressl_ctx, clt->clt_buf,
+ clt->clt_buflen, &len);
+ if (ret == RESSL_READ_AGAIN || ret == RESSL_WRITE_AGAIN) {
+ goto retry;
+ } else if (ret != 0) {
+ what |= EVBUFFER_ERROR;
+ goto err;
+ }
+ evbuffer_drain(bufev->output, len);
+ }
+ if (clt->clt_buf != NULL) {
+ free(clt->clt_buf);
+ clt->clt_buf = NULL;
+ clt->clt_buflen = 0;
+ }
+
+ if (EVBUFFER_LENGTH(bufev->output) != 0)
+ server_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+
+ if (bufev->writecb != NULL &&
+ EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
+ (*bufev->writecb)(bufev, bufev->cbarg);
+ return;
+
+retry:
+ if (clt->clt_buflen != 0)
+ server_bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+ return;
+
+err:
+ if (clt->clt_buf != NULL) {
+ free(clt->clt_buf);
+ clt->clt_buf = NULL;
+ clt->clt_buflen = 0;
+ }
+ (*bufev->errorcb)(bufev, what, bufev->cbarg);
+}
+
+void
server_input(struct client *clt)
{
struct server_config *srv_conf = clt->clt_srv_conf;
@@ -371,8 +533,7 @@ server_input(struct client *clt)
evbuffercb inwr = server_write;
if (server_httpdesc_init(clt) == -1) {
- server_close(clt,
- "failed to allocate http descriptor");
+ server_close(clt, "failed to allocate http descriptor");
return;
}
@@ -389,6 +550,13 @@ server_input(struct client *clt)
return;
}
+ if (srv_conf->flags & SRVFLAG_SSL) {
+ event_set(&clt->clt_bev->ev_read, clt->clt_s, EV_READ,
+ server_ssl_readcb, clt->clt_bev);
+ event_set(&clt->clt_bev->ev_write, clt->clt_s, EV_WRITE,
+ server_ssl_writecb, clt->clt_bev);
+ }
+
bufferevent_settimeout(clt->clt_bev,
srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec);
bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE);
@@ -417,6 +585,8 @@ server_write(struct bufferevent *bev, void *arg)
void
server_dump(struct client *clt, const void *buf, size_t len)
{
+ size_t outlen;
+
if (!len)
return;
@@ -426,11 +596,9 @@ server_dump(struct client *clt, const void *buf, size_t len)
* of non-blocking events etc. This is useful to print an
* error message before gracefully closing the client.
*/
-#if 0
- if (cre->ssl != NULL)
- (void)SSL_write(cre->ssl, buf, len);
+ if (clt->clt_ressl_ctx != NULL)
+ (void)ressl_write(clt->clt_ressl_ctx, buf, len, &outlen);
else
-#endif
(void)write(clt->clt_s, buf, len);
}
@@ -573,6 +741,13 @@ server_accept(int fd, short event, void *arg)
return;
}
+ if (srv->srv_conf.flags & SRVFLAG_SSL) {
+ event_again(&clt->clt_ev, clt->clt_s, EV_TIMEOUT|EV_READ,
+ server_accept_ssl, &clt->clt_tv_start,
+ &srv->srv_conf.timeout, clt);
+ return;
+ }
+
server_input(clt);
return;
@@ -590,6 +765,41 @@ server_accept(int fd, short event, void *arg)
}
void
+server_accept_ssl(int fd, short event, void *arg)
+{
+ struct client *clt = (struct client *)arg;
+ struct server *srv = (struct server *)clt->clt_srv;
+ int ret;
+
+ if (event == EV_TIMEOUT) {
+ server_close(clt, "SSL accept timeout");
+ return;
+ }
+
+ if (srv->srv_ressl_ctx == NULL)
+ fatalx("NULL ressl context");
+
+ ret = ressl_accept_socket(srv->srv_ressl_ctx, &clt->clt_ressl_ctx,
+ clt->clt_s);
+ if (ret == RESSL_READ_AGAIN) {
+ event_again(&clt->clt_ev, clt->clt_s, EV_TIMEOUT|EV_READ,
+ server_accept_ssl, &clt->clt_tv_start,
+ &srv->srv_conf.timeout, clt);
+ } else if (ret == RESSL_WRITE_AGAIN) {
+ event_again(&clt->clt_ev, clt->clt_s, EV_TIMEOUT|EV_WRITE,
+ server_accept_ssl, &clt->clt_tv_start,
+ &srv->srv_conf.timeout, clt);
+ } else if (ret != 0) {
+ log_warnx("%s: SSL accept failed - %s", __func__,
+ ressl_error(srv->srv_ressl_ctx));
+ return;
+ }
+
+ server_input(clt);
+ return;
+}
+
+void
server_inflight_dec(struct client *clt, const char *why)
{
if (clt != NULL) {
@@ -728,6 +938,10 @@ server_close(struct client *clt, const char *msg)
if (clt->clt_s != -1)
close(clt->clt_s);
+ if (clt->clt_ressl_ctx != NULL)
+ ressl_close(clt->clt_ressl_ctx);
+ ressl_free(clt->clt_ressl_ctx);
+
server_inflight_dec(clt, __func__);
if (clt->clt_log != NULL)