summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorflorian <florian@openbsd.org>2015-07-18 05:41:18 +0000
committerflorian <florian@openbsd.org>2015-07-18 05:41:18 +0000
commitf5d55328fdd7734f455a1ed893a5e7db6e2d437f (patch)
tree8fac9636b258fffef6a9b56354c9ea93a0a56e4d
parentHave tftpd provide a block of random data when clients request the file (diff)
downloadwireguard-openbsd-f5d55328fdd7734f455a1ed893a5e7db6e2d437f.tar.xz
wireguard-openbsd-f5d55328fdd7734f455a1ed893a5e7db6e2d437f.zip
Implement HTTP Strict Transport Security (HSTS).
Input & OK reyk
-rw-r--r--usr.sbin/httpd/config.c7
-rw-r--r--usr.sbin/httpd/httpd.conf.516
-rw-r--r--usr.sbin/httpd/httpd.h9
-rw-r--r--usr.sbin/httpd/parse.y37
-rw-r--r--usr.sbin/httpd/server_http.c30
5 files changed, 88 insertions, 11 deletions
diff --git a/usr.sbin/httpd/config.c b/usr.sbin/httpd/config.c
index 3c889906410..046e63cedfc 100644
--- a/usr.sbin/httpd/config.c
+++ b/usr.sbin/httpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.39 2015/07/15 16:00:39 jsing Exp $ */
+/* $OpenBSD: config.c,v 1.40 2015/07/18 05:41:18 florian Exp $ */
/*
* Copyright (c) 2011 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -436,6 +436,11 @@ config_getserver_config(struct httpd *env, struct server *srv,
goto fail;
}
+ f = SRVFLAG_SERVER_HSTS;
+ srv_conf->flags |= parent->flags & f;
+ srv_conf->hsts_max_age = parent->hsts_max_age;
+ srv_conf->hsts_subdomains = parent->hsts_subdomains;
+
memcpy(&srv_conf->timeout, &parent->timeout,
sizeof(srv_conf->timeout));
srv_conf->maxrequests = parent->maxrequests;
diff --git a/usr.sbin/httpd/httpd.conf.5 b/usr.sbin/httpd/httpd.conf.5
index b3eaad852a9..cbf651ca461 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.64 2015/07/15 17:10:47 jsing Exp $
+.\" $OpenBSD: httpd.conf.5,v 1.65 2015/07/18 05:41:18 florian Exp $
.\"
.\" Copyright (c) 2014, 2015 Reyk Floeter <reyk@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 15 2015 $
+.Dd $Mdocdate: July 18 2015 $
.Dt HTTPD.CONF 5
.Os
.Sh NAME
@@ -262,6 +262,18 @@ root directory of
.Xr httpd 8
and defaults to
.Pa /run/slowcgi.sock .
+.It Ic hsts Oo Ar option Oc
+Enable HTTP Strict Transport Security.
+Valid options are:
+.Bl -tag -width Ds
+.It Ic max-age Ar seconds
+Set the maximum time in seconds a receiving user agent should regard
+this host as a HSTS host.
+The default is one year.
+.It Ic subdomains
+Signal to the receiving user agent that this host and all sub domains
+of the host's domain should be considered HSTS hosts.
+.El
.It Ic listen on Ar address Oo Ic tls Oc Ic port Ar number
Set the listen address and port.
This statement can be specified multiple times.
diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h
index 2cb7934b536..1b7e528d134 100644
--- a/usr.sbin/httpd/httpd.h
+++ b/usr.sbin/httpd/httpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: httpd.h,v 1.88 2015/07/16 16:29:25 florian Exp $ */
+/* $OpenBSD: httpd.h,v 1.89 2015/07/18 05:41:18 florian Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -68,6 +68,7 @@
#define SERVER_OUTOF_FD_RETRIES 5
#define SERVER_MAX_PREFETCH 256
#define SERVER_MIN_PREFETCHED 32
+#define SERVER_HSTS_DEFAULT_AGE 31536000
#define MEDIATYPE_NAMEMAX 128 /* file name extension */
#define MEDIATYPE_TYPEMAX 64 /* length of type/subtype */
@@ -351,13 +352,14 @@ SPLAY_HEAD(client_tree, client);
#define SRVFLAG_NO_BLOCK 0x00080000
#define SRVFLAG_LOCATION_MATCH 0x00100000
#define SRVFLAG_SERVER_MATCH 0x00200000
+#define SRVFLAG_SERVER_HSTS 0x00400000
#define SRVFLAG_BITS \
"\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX" \
"\05ROOT\06LOCATION\07FCGI\10NO_FCGI\11LOG\12NO_LOG\13SOCKET" \
"\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG" \
"\21AUTH\22NO_AUTH\23BLOCK\24NO_BLOCK\25LOCATION_MATCH" \
- "\26SERVER_MATCH"
+ "\26SERVER_MATCH\27SERVER_HSTS"
#define TCPFLAG_NODELAY 0x01
#define TCPFLAG_NNODELAY 0x02
@@ -443,6 +445,9 @@ struct server_config {
char *return_uri;
off_t return_uri_len;
+ int hsts_max_age;
+ int hsts_subdomains;
+
TAILQ_ENTRY(server_config) entry;
};
TAILQ_HEAD(serverhosts, server_config);
diff --git a/usr.sbin/httpd/parse.y b/usr.sbin/httpd/parse.y
index 0870819c9e6..b75f8b7b626 100644
--- a/usr.sbin/httpd/parse.y
+++ b/usr.sbin/httpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.70 2015/07/16 19:05:28 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.71 2015/07/18 05:41:18 florian Exp $ */
/*
* Copyright (c) 2007 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -133,7 +133,7 @@ typedef struct {
%token COMBINED CONNECTION DHE DIRECTORY ECDHE ERR FCGI INDEX IP KEY LISTEN
%token LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY ON PORT PREFORK PROTOCOLS
%token REQUEST REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP TIMEOUT
-%token TLS TYPES
+%token TLS TYPES HSTS MAXAGE SUBDOMAINS
%token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS
%token <v.string> STRING
%token <v.number> NUMBER
@@ -256,6 +256,8 @@ server : SERVER optmatch STRING {
HTTPD_TLS_ECDHE_CURVE,
sizeof(s->srv_conf.tls_ecdhe_curve));
+ s->srv_conf.hsts_max_age = SERVER_HSTS_DEFAULT_AGE;
+
if (last_server_id == INT_MAX) {
yyerror("too many servers defined");
free(s);
@@ -556,6 +558,34 @@ serveroptsl : LISTEN ON STRING opttls port {
parentsrv = NULL;
}
| include
+ | hsts {
+ if (parentsrv != NULL) {
+ yyerror("hsts inside location");
+ YYERROR;
+ }
+ srv->srv_conf.flags |= SRVFLAG_SERVER_HSTS;
+ }
+ ;
+
+hsts : HSTS '{' optnl hstsflags_l '}'
+ | HSTS hstsflags
+ | HSTS
+ ;
+
+hstsflags_l : hstsflags optcommanl hstsflags_l
+ | hstsflags optnl
+ ;
+
+hstsflags : MAXAGE NUMBER {
+ if ($2 < 0 || $2 > INT_MAX) {
+ yyerror("invalid number of seconds: %lld", $2);
+ YYERROR;
+ }
+ srv_conf->hsts_max_age = $2;
+ }
+ | SUBDOMAINS {
+ srv->srv_conf.hsts_subdomains = 1;
+ }
;
fastcgi : NO FCGI {
@@ -1115,6 +1145,7 @@ lookup(char *s)
{ "ecdhe", ECDHE },
{ "error", ERR },
{ "fastcgi", FCGI },
+ { "hsts", HSTS },
{ "include", INCLUDE },
{ "index", INDEX },
{ "ip", IP },
@@ -1125,6 +1156,7 @@ lookup(char *s)
{ "logdir", LOGDIR },
{ "match", MATCH },
{ "max", MAXIMUM },
+ { "max-age", MAXAGE },
{ "no", NO },
{ "nodelay", NODELAY },
{ "on", ON },
@@ -1141,6 +1173,7 @@ lookup(char *s)
{ "socket", SOCKET },
{ "strip", STRIP },
{ "style", STYLE },
+ { "subdomains", SUBDOMAINS },
{ "syslog", SYSLOG },
{ "tcp", TCP },
{ "timeout", TIMEOUT },
diff --git a/usr.sbin/httpd/server_http.c b/usr.sbin/httpd/server_http.c
index 9a6609e58f7..75cecc74257 100644
--- a/usr.sbin/httpd/server_http.c
+++ b/usr.sbin/httpd/server_http.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: server_http.c,v 1.89 2015/07/16 19:05:28 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.90 2015/07/18 05:41:19 florian Exp $ */
/*
* Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -735,13 +735,12 @@ server_http_parsehost(char *host, char *buf, size_t len, int *portval)
void
server_abort_http(struct client *clt, u_int code, const char *msg)
{
- struct server *srv = clt->clt_srv;
- struct server_config *srv_conf = &srv->srv_conf;
+ struct server_config *srv_conf = clt->clt_srv_conf;
struct bufferevent *bev = clt->clt_bev;
struct http_descriptor *desc = clt->clt_descreq;
const char *httperr = NULL, *style;
char *httpmsg, *body = NULL, *extraheader = NULL;
- char tmbuf[32], hbuf[128];
+ char tmbuf[32], hbuf[128], *hstsheader = NULL;
char buf[IBUF_READ_SIZE];
int bodylen;
@@ -828,6 +827,14 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
code, httperr, style, code, httperr, HTTPD_SERVERNAME)) == -1)
goto done;
+ if (srv_conf->flags & SRVFLAG_SERVER_HSTS) {
+ if (asprintf(&hstsheader, "Strict-Transport-Security: "
+ "max-age=%d%s\r\n", srv_conf->hsts_max_age,
+ srv_conf->hsts_subdomains == 0 ? "" :
+ " ; includeSubDomains") == -1)
+ goto done;
+ }
+
/* Add basic HTTP headers */
if (asprintf(&httpmsg,
"HTTP/1.0 %03d %s\r\n"
@@ -837,10 +844,12 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
"Content-Type: text/html\r\n"
"Content-Length: %d\r\n"
"%s"
+ "%s"
"\r\n"
"%s",
code, httperr, tmbuf, HTTPD_SERVERNAME, bodylen,
extraheader == NULL ? "" : extraheader,
+ hstsheader == NULL ? "" : hstsheader,
desc->http_method == HTTP_METHOD_HEAD ? "" : body) == -1)
goto done;
@@ -851,6 +860,7 @@ server_abort_http(struct client *clt, u_int code, const char *msg)
done:
free(body);
free(extraheader);
+ free(hstsheader);
if (msg == NULL)
msg = "\"\"";
if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1) {
@@ -1210,6 +1220,7 @@ int
server_response_http(struct client *clt, u_int code,
struct media_type *media, off_t size, time_t mtime)
{
+ struct server_config *srv_conf = clt->clt_srv_conf;
struct http_descriptor *desc = clt->clt_descreq;
struct http_descriptor *resp = clt->clt_descresp;
const char *error;
@@ -1257,6 +1268,17 @@ server_response_http(struct client *clt, u_int code,
kv_add(&resp->http_headers, "Last-Modified", tmbuf) == NULL)
return (-1);
+ /* HSTS header */
+ if (srv_conf->flags & SRVFLAG_SERVER_HSTS) {
+ if ((cl =
+ kv_add(&resp->http_headers, "Strict-Transport-Security",
+ NULL)) == NULL ||
+ kv_set(cl, "max-age=%d%s", srv_conf->hsts_max_age,
+ srv_conf->hsts_subdomains == 0 ? "" :
+ " ; includeSubDomains") == -1)
+ return (-1);
+ }
+
/* Date header is mandatory and should be added as late as possible */
if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0 ||
kv_add(&resp->http_headers, "Date", tmbuf) == NULL)