OK?

diff --git httpd.conf.5 httpd.conf.5
index b3eaad8..bfca29f 100644
--- httpd.conf.5
+++ httpd.conf.5
@@ -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 httpd.h httpd.h
index 2cb7934..9596000 100644
--- httpd.h
+++ httpd.h
@@ -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;
 
+       int64_t                  hsts_max_age;
+       int                      hsts_subdomains;
+
        TAILQ_ENTRY(server_config) entry;
 };
 TAILQ_HEAD(serverhosts, server_config);
diff --git parse.y parse.y
index 0870819..8dfad1a 100644
--- parse.y
+++ parse.y
@@ -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 = -1;
+
                        if (last_server_id == INT_MAX) {
                                yyerror("too many servers defined");
                                free(s);
@@ -556,6 +558,30 @@ 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         {
+                       srv_conf->hsts_max_age = $2;
+               }
+               | SUBDOMAINS            {
+                       srv->srv_conf.hsts_subdomains = 1;
+               }
                ;
 
 fastcgi                : NO FCGI               {
@@ -1115,6 +1141,7 @@ lookup(char *s)
                { "ecdhe",              ECDHE },
                { "error",              ERR },
                { "fastcgi",            FCGI },
+               { "hsts",               HSTS },
                { "include",            INCLUDE },
                { "index",              INDEX },
                { "ip",                 IP },
@@ -1125,6 +1152,7 @@ lookup(char *s)
                { "logdir",             LOGDIR },
                { "match",              MATCH },
                { "max",                MAXIMUM },
+               { "max-age",            MAXAGE },
                { "no",                 NO },
                { "nodelay",            NODELAY },
                { "on",                 ON },
@@ -1141,6 +1169,7 @@ lookup(char *s)
                { "socket",             SOCKET },
                { "strip",              STRIP },
                { "style",              STYLE },
+               { "subdomains",         SUBDOMAINS },
                { "syslog",             SYSLOG },
                { "tcp",                TCP },
                { "timeout",            TIMEOUT },
diff --git server_http.c server_http.c
index 9a6609e..8bdeade 100644
--- server_http.c
+++ server_http.c
@@ -741,7 +741,7 @@ server_abort_http(struct client *clt, u_int code, const 
char *msg)
        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 +828,16 @@ 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=%lld%s\r\n",
+                   srv_conf->hsts_max_age == -1 ? SERVER_HSTS_DEFAULT_AGE :
+                   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 +847,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 +863,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 +1223,8 @@ int
 server_response_http(struct client *clt, u_int code,
     struct media_type *media, off_t size, time_t mtime)
 {
+       struct server           *srv = clt->clt_srv;
+       struct server_config    *srv_conf = &srv->srv_conf;
        struct http_descriptor  *desc = clt->clt_descreq;
        struct http_descriptor  *resp = clt->clt_descresp;
        const char              *error;
@@ -1257,6 +1272,18 @@ 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=%lld%s", srv_conf->hsts_max_age == -1 ?
+                   SERVER_HSTS_DEFAULT_AGE : 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)

-- 
I'm not entirely sure you are real.

Reply via email to