You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2017/09/15 10:35:53 UTC

svn commit: r1808444 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_md.xml modules/md/md.h modules/md/md_version.h modules/md/mod_md.c modules/md/mod_md_config.c modules/md/mod_md_config.h

Author: icing
Date: Fri Sep 15 10:35:53 2017
New Revision: 1808444

URL: http://svn.apache.org/viewvc?rev=1808444&view=rev
Log:
On the trunk:

mod_md: v0.9.6: a "MDRequireHttps permament" configured domain automatically sends out HSTS (rfc 6797) headers in https: responses. 


Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/docs/manual/mod/mod_md.xml
    httpd/httpd/trunk/modules/md/md.h
    httpd/httpd/trunk/modules/md/md_version.h
    httpd/httpd/trunk/modules/md/mod_md.c
    httpd/httpd/trunk/modules/md/mod_md_config.c
    httpd/httpd/trunk/modules/md/mod_md_config.h

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1808444&r1=1808443&r2=1808444&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Fri Sep 15 10:35:53 2017
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) mod_md: v0.9.6: a "MDRequireHttps permament" configured domain automatically sends out
+     HSTS (rfc 6797) headers in https: responses. [Stefan Eissing]
+
   *) mod_ssl: adding ssl_policies.h[.in] for policy cipher/protocol definitions. Use 
      update_policies.py to update manually from Mozilla JSON definitions at
      https://statics.tls.security.mozilla.org/server-side-tls-conf.json

Modified: httpd/httpd/trunk/docs/manual/mod/mod_md.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_md.xml?rev=1808444&r1=1808443&r2=1808444&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_md.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_md.xml Fri Sep 15 10:35:53 2017
@@ -501,6 +501,17 @@ MDRequireHttps permanent
 </ManagedDomain>
                 </highlight>
             </example>
+            <p>When you configure MDRequireHttps permanent, an additional security 
+            feature is automatically applied: HSTS. This adds the header 
+            Strict-Transport-Security to responses sent out via https:. 
+            Basically, this instructs the browser to only perform secure 
+            communications with that domain. This instruction holds for the 
+            amount of time specified in the header as 'max-age'. 
+            This is about half a year as generated by mod_md.
+            </p><p>
+            It is therefore advisable to first test the MDRequireHttps temporary 
+            configuration and switch to permanent only once that works satisfactory.
+            </p>
         </usage>
     </directivesynopsis>
 

Modified: httpd/httpd/trunk/modules/md/md.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md.h?rev=1808444&r1=1808443&r2=1808444&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md.h (original)
+++ httpd/httpd/trunk/modules/md/md.h Fri Sep 15 10:35:53 2017
@@ -32,6 +32,10 @@ struct md_pkey_spec_t;
 #define MD_PKEY_RSA_BITS_MIN       2048
 #define MD_PKEY_RSA_BITS_DEF       2048
 
+/* Minimum age for the HSTS header (RFC 6797), considered appropriate by Mozilla Security */
+#define MD_HSTS_HEADER             "Strict-Transport-Security"
+#define MD_HSTS_MAX_AGE_DEFAULT    15768000
+
 typedef enum {
     MD_S_UNKNOWN,                   /* MD has not been analysed yet */
     MD_S_INCOMPLETE,                /* MD is missing necessary information, cannot go live */

Modified: httpd/httpd/trunk/modules/md/md_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/md_version.h?rev=1808444&r1=1808443&r2=1808444&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/md_version.h (original)
+++ httpd/httpd/trunk/modules/md/md_version.h Fri Sep 15 10:35:53 2017
@@ -26,7 +26,7 @@
  * @macro
  * Version number of the md module as c string
  */
-#define MOD_MD_VERSION "0.9.5"
+#define MOD_MD_VERSION "0.9.6"
 
 /**
  * @macro
@@ -34,7 +34,7 @@
  * release. This is a 24 bit number with 8 bits for major number, 8 bits
  * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
  */
-#define MOD_MD_VERSION_NUM 0x000905
+#define MOD_MD_VERSION_NUM 0x000906
 
 #define MD_EXPERIMENTAL 0
 #define MD_ACME_DEF_URL    "https://acme-v01.api.letsencrypt.org/directory"

Modified: httpd/httpd/trunk/modules/md/mod_md.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md.c?rev=1808444&r1=1808443&r2=1808444&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md.c (original)
+++ httpd/httpd/trunk/modules/md/mod_md.c Fri Sep 15 10:35:53 2017
@@ -253,7 +253,7 @@ static apr_status_t assign_to_servers(md
                 /* We require https for this MD, but do we have port 443 (or a mapped one)
                  * available? */
                 if (mc->local_443 <= 0) {
-                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10089)
+                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO()
                                  "MDPortMap says there is no port for https (443), "
                                  "but MD %s is configured to require https. This "
                                  "only works when a 443 port is available.", md->name);
@@ -275,7 +275,7 @@ static apr_status_t assign_to_servers(md
                 if (!s_https) {
                     /* Did not find any server_rec that matches this MD *and* has an
                      * s->addrs match for the https port. Suspicious. */
-                    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(10090)
+                    ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO()
                                  "MD %s is configured to require https, but there seems to be "
                                  "no VirtualHost for it that has port %d in its address list. "
                                  "This looks as if it will not work.", 
@@ -697,7 +697,7 @@ static apr_status_t run_watchdog(int sta
 
             now = apr_time_now();
             if (APLOGdebug(wd->s)) {
-                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10091)
+                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO()
                              "next run in %s", md_print_duration(ptemp, next_run - now));
             }
             wd_set_interval(wd->watchdog, next_run - now, wd, run_watchdog);
@@ -881,6 +881,7 @@ static apr_status_t md_post_config(apr_p
     apr_status_t rv = APR_SUCCESS;
     int i;
 
+    md_config_post_config(s, p);
     sc = md_config_get(s);
     mc = sc->mc;
     
@@ -1005,14 +1006,14 @@ static apr_status_t md_get_certificate(s
         assert(sc->mc);
         assert(sc->mc->store);
         if (APR_SUCCESS != (rv = md_reg_init(&reg, p, sc->mc->store, sc->mc->proxy_url))) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10092) "init registry");
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO() "init registry");
             return rv;
         }
 
         md = md_reg_get(reg, sc->assigned->name, p);
             
         if (APR_SUCCESS != (rv = md_reg_get_cred_files(reg, md, p, pkeyfile, pcertfile))) {
-            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10093) 
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO() 
                          "retrieving credentials for MD %s", md->name);
             return rv;
         }
@@ -1169,34 +1170,44 @@ static int md_require_https_maybe(reques
     const char *s;
     int status;
     
-    if (strncmp(WELL_KNOWN_PREFIX, r->parsed_uri.path, sizeof(WELL_KNOWN_PREFIX)-1)) {
+    if (opt_ssl_is_https 
+        && strncmp(WELL_KNOWN_PREFIX, r->parsed_uri.path, sizeof(WELL_KNOWN_PREFIX)-1)) {
+        
         sc = ap_get_module_config(r->server->module_config, &md_module);
-        if (sc && sc->assigned && sc->assigned->require_https > MD_REQUIRE_OFF 
-            && opt_ssl_is_https && !opt_ssl_is_https(r->connection)) {
-            /* Do not have https:, but require it. Redirect the request accordingly. 
-             */
-            if (r->method_number == M_GET) {
-                /* safe to use the old-fashioned codes */
-                status = ((MD_REQUIRE_PERMANENT == sc->assigned->require_https)? 
-                          HTTP_MOVED_PERMANENTLY : HTTP_MOVED_TEMPORARILY);
+        if (sc && sc->assigned && sc->assigned->require_https > MD_REQUIRE_OFF) {
+            if (opt_ssl_is_https(r->connection)) {
+                /* Using https:
+                 * if 'permanent' and no one else set a HSTS header already, do it */
+                if (sc->assigned->require_https == MD_REQUIRE_PERMANENT 
+                    && sc->mc->hsts_header && !apr_table_get(r->headers_out, MD_HSTS_HEADER)) {
+                    apr_table_setn(r->headers_out, MD_HSTS_HEADER, sc->mc->hsts_header);
+                }
             }
             else {
-                /* these should keep the method unchanged on retry */
-                status = ((MD_REQUIRE_PERMANENT == sc->assigned->require_https)? 
-                          HTTP_PERMANENT_REDIRECT : HTTP_TEMPORARY_REDIRECT);
-            }
-            
-            s = ap_construct_url(r->pool, r->uri, r);
-            if (APR_SUCCESS == apr_uri_parse(r->pool, s, &uri)) {
-                uri.scheme = (char*)"https";
-                uri.port = 443;
-                uri.port_str = (char*)"443";
-                uri.query = r->parsed_uri.query;
-                uri.fragment = r->parsed_uri.fragment;
-                s = apr_uri_unparse(r->pool, &uri, APR_URI_UNP_OMITUSERINFO);
-                if (s && *s) {
-                    apr_table_setn(r->headers_out, "Location", s);
-                    return status;
+                /* Not using https:, but require it. Redirect. */
+                if (r->method_number == M_GET) {
+                    /* safe to use the old-fashioned codes */
+                    status = ((MD_REQUIRE_PERMANENT == sc->assigned->require_https)? 
+                              HTTP_MOVED_PERMANENTLY : HTTP_MOVED_TEMPORARILY);
+                }
+                else {
+                    /* these should keep the method unchanged on retry */
+                    status = ((MD_REQUIRE_PERMANENT == sc->assigned->require_https)? 
+                              HTTP_PERMANENT_REDIRECT : HTTP_TEMPORARY_REDIRECT);
+                }
+                
+                s = ap_construct_url(r->pool, r->uri, r);
+                if (APR_SUCCESS == apr_uri_parse(r->pool, s, &uri)) {
+                    uri.scheme = (char*)"https";
+                    uri.port = 443;
+                    uri.port_str = (char*)"443";
+                    uri.query = r->parsed_uri.query;
+                    uri.fragment = r->parsed_uri.fragment;
+                    s = apr_uri_unparse(r->pool, &uri, APR_URI_UNP_OMITUSERINFO);
+                    if (s && *s) {
+                        apr_table_setn(r->headers_out, "Location", s);
+                        return status;
+                    }
                 }
             }
         }
@@ -1233,7 +1244,7 @@ static void md_hooks(apr_pool_t *pool)
     /* answer challenges *very* early, before any configured authentication may strike */
     ap_hook_post_read_request(md_http_challenge_pr, NULL, NULL, APR_HOOK_MIDDLE);
     /* redirect to https if configured */
-    ap_hook_fixups(md_require_https_maybe, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_fixups(md_require_https_maybe, NULL, NULL, APR_HOOK_LAST);
 
     APR_REGISTER_OPTIONAL_FN(md_is_managed);
     APR_REGISTER_OPTIONAL_FN(md_get_certificate);

Modified: httpd/httpd/trunk/modules/md/mod_md_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md_config.c?rev=1808444&r1=1808443&r2=1808444&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_config.c (original)
+++ httpd/httpd/trunk/modules/md/mod_md_config.c Fri Sep 15 10:35:53 2017
@@ -59,7 +59,9 @@ static md_mod_conf_t defmc = {
     443,
     0,
     0,
-    NULL
+    MD_HSTS_MAX_AGE_DEFAULT,
+    NULL,
+    NULL,
 };
 
 /* Default server specific setting */
@@ -770,6 +772,21 @@ const command_rec md_cmds[] = {
     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
 };
 
+apr_status_t md_config_post_config(server_rec *s, apr_pool_t *p)
+{
+    md_srv_conf_t *sc;
+    md_mod_conf_t *mc;
+
+    sc = md_config_get(s);
+    mc = sc->mc;
+
+    mc->hsts_header = NULL;
+    if (mc->hsts_max_age > 0) {
+        mc->hsts_header = apr_psprintf(p, "max-age=%d", mc->hsts_max_age);
+    }
+    
+    return APR_SUCCESS;
+}
 
 static md_srv_conf_t *config_get_int(server_rec *s, apr_pool_t *p)
 {

Modified: httpd/httpd/trunk/modules/md/mod_md_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md_config.h?rev=1808444&r1=1808443&r2=1808444&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_config.h (original)
+++ httpd/httpd/trunk/modules/md/mod_md_config.h Fri Sep 15 10:35:53 2017
@@ -45,8 +45,9 @@ typedef struct {
     int local_443;                     /* On which port https:443 arrives */
     int can_http;                      /* Does someone listen to the local port 80 equivalent? */
     int can_https;                     /* Does someone listen to the local port 443 equivalent? */
-
-    apr_array_header_t *unused_names;  /* post config, names of all MDs not linked to a vhost */
+    int hsts_max_age;                  /* max-age of HSTS (rfc6797) header */
+    const char *hsts_header;           /* computed HTST header to use or NULL */
+    apr_array_header_t *unused_names;  /* post config, names of all MDs not assigned to a vhost */
 } md_mod_conf_t;
 
 typedef struct md_srv_conf_t {
@@ -78,6 +79,8 @@ void *md_config_merge_svr(apr_pool_t *po
 
 extern const command_rec md_cmds[];
 
+apr_status_t md_config_post_config(server_rec *s, apr_pool_t *p);
+
 /* Get the effective md configuration for the connection */
 md_srv_conf_t *md_config_cget(conn_rec *c);
 /* Get the effective md configuration for the server */