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/01 12:11:39 UTC

svn commit: r1806939 [2/2] - in /httpd/httpd/trunk: ./ docs/manual/mod/ modules/md/ modules/ssl/

Modified: httpd/httpd/trunk/modules/md/mod_md.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md.c?rev=1806939&r1=1806938&r2=1806939&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md.c (original)
+++ httpd/httpd/trunk/modules/md/mod_md.c Fri Sep  1 12:11:38 2017
@@ -78,6 +78,9 @@ static void md_merge_srv(md_t *md, md_sr
     if (md->drive_mode == MD_DRIVE_DEFAULT) {
         md->drive_mode = md_config_geti(md->sc, MD_CONFIG_DRIVE_MODE);
     }
+    if (md->renew_norm <= 0) {
+        md->renew_norm = md_config_get_interval(md->sc, MD_CONFIG_RENEW_NORM);
+    }
     if (md->renew_window <= 0) {
         md->renew_window = md_config_get_interval(md->sc, MD_CONFIG_RENEW_WINDOW);
     }
@@ -87,6 +90,10 @@ static void md_merge_srv(md_t *md, md_sr
     if (!md->ca_challenges && md->sc->ca_challenges) {
         md->ca_challenges = apr_array_copy(p, md->sc->ca_challenges);
     }        
+    if (!md->pkey_spec) {
+        md->pkey_spec = md->sc->pkey_spec;
+        
+    }
 }
 
 static apr_status_t check_coverage(md_t *md, const char *domain, server_rec *s, apr_pool_t *p)
@@ -460,6 +467,9 @@ static apr_status_t drive_md(md_watchdog
     int errored, renew;
     char ts[APR_RFC822_DATE_LEN];
     
+    if (md->state == MD_S_MISSING) {
+        rv = APR_INCOMPLETE;
+    }
     if (md->state == MD_S_COMPLETE && !md->expires) {
         /* This is our indicator that we did already renewed this managed domain
          * successfully and only wait on the next restart for it to activate */
@@ -508,7 +518,7 @@ static apr_status_t run_watchdog(int sta
     md_watchdog *wd = baton;
     apr_status_t rv = APR_SUCCESS;
     md_t *md;
-    apr_interval_time_t interval, now;
+    apr_time_t next_run, now;
     int i;
     
     switch (state) {
@@ -519,9 +529,6 @@ static apr_status_t run_watchdog(int sta
         case AP_WATCHDOG_STATE_RUNNING:
             assert(wd->reg);
             
-            /* normally, we'd like to run at least twice a day */
-            interval = apr_time_from_sec(MD_SECS_PER_DAY / 2);
-
             wd->all_valid = 1;
             wd->valid_not_before = 0;
             wd->processed_count = 0;
@@ -536,7 +543,13 @@ static apr_status_t run_watchdog(int sta
             for (i = 0; i < wd->mds->nelts; ++i) {
                 md = APR_ARRAY_IDX(wd->mds, i, md_t *);
                 
-                if (APR_SUCCESS != (rv = drive_md(wd, md, ptemp))) {
+                rv = drive_md(wd, md, ptemp);
+                
+                if (APR_STATUS_IS_INCOMPLETE(rv)) {
+                    /* configuration not complete, this MD cannot be driven further */
+                    wd->all_valid = 0;
+                }
+                else if (APR_SUCCESS != rv) {
                     wd->all_valid = 0;
                     ++wd->error_count;
                     ap_log_error( APLOG_MARK, APLOG_ERR, rv, wd->s, APLOGNO(10056) 
@@ -546,50 +559,57 @@ static apr_status_t run_watchdog(int sta
 
             /* Determine when we want to run next */
             wd->error_runs = wd->error_count? (wd->error_runs + 1) : 0;
+
             if (wd->all_valid) {
-                now = apr_time_now();
-                if (wd->next_valid > now && (wd->next_valid - now < interval)) {
-                    interval = wd->next_valid - now;
-                    ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s, 
-                                 "Delaying activation of %d Managed Domain%s by %s", 
-                                 wd->processed_count, (wd->processed_count > 1)? "s have" : " has",
-                                 md_print_duration(ptemp, interval));
-                }
-                else {
-                    ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s, 
-                                 "all managed domains are valid");
-                }
+                ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s, "all managed domains are valid");
             }
-            else {
-                /* back off duration, depending on the errors we encounter in a row */
-                interval = apr_time_from_sec(5 << (wd->error_runs - 1));
-                if (interval > apr_time_from_sec(60*60)) {
-                    interval = apr_time_from_sec(60*60);
-                }
-                ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10057) 
-                             "encountered errors for the %d. time, next run in %d seconds",
-                             wd->error_runs, (int)apr_time_sec(interval));
+            else if (wd->error_count == 0) {
+                ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO() 
+                             "all managed domains driven as far as possible");
+            }
+            
+            now = apr_time_now();
+            /* normally, we'd like to run at least twice a day */
+            next_run = now + apr_time_from_sec(MD_SECS_PER_DAY / 2);
+            
+            /* Unless we know of an MD change before that */
+            if (wd->next_change > 0 && wd->next_change < next_run) {
+                next_run = wd->next_change;
             }
             
-            /* We follow the chosen min_interval for re-evaluation, unless we
-             * know of a change (renewal) that happens before that. */
-            if (wd->next_change) {
-                apr_interval_time_t until_next = wd->next_change - apr_time_now();
-                if (until_next < interval) {
-                    interval = until_next;
+            /* Or have to activate a new cert even before that */
+            if (wd->next_valid > now && wd->next_valid < next_run) {
+                next_run = wd->next_valid;
+                ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s, 
+                             "Delaying activation of %d Managed Domain%s by %s", 
+                             wd->processed_count, (wd->processed_count > 1)? "s have" : " has",
+                             md_print_duration(ptemp, next_run - now));
+            }
+            
+            /* Or encountered errors and like to retry even before that */
+            if (wd->error_count > 0) {
+                apr_interval_time_t delay;
+                
+                /* back off duration, depending on the errors we encounter in a row */
+                delay = apr_time_from_sec(5 << (wd->error_runs - 1));
+                if (delay > apr_time_from_sec(60*60)) {
+                    delay = apr_time_from_sec(60*60);
+                }
+                if (now + delay < next_run) {
+                    ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10057) 
+                                 "encountered errors for the %d. time, next try by %s",
+                                 wd->error_runs, md_print_duration(ptemp, delay));
+                    next_run = now + delay;
                 }
             }
             
-            /* Set when we'd like to be run next time. 
-             * TODO: it seems that this is really only ticking down when the server
-             * runs. When you wake up a hibernated machine, the watchdog will not run right away 
-             */
             if (APLOGdebug(wd->s)) {
-                ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, "next run in %s",
-                             md_print_duration(ptemp, interval));
+                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, interval, wd, run_watchdog);
+            wd_set_interval(wd->watchdog, next_run - now, wd, run_watchdog);
             break;
+            
         case AP_WATCHDOG_STATE_STOPPING:
             ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10058)
                          "md watchdog stopping");
@@ -684,7 +704,7 @@ static apr_status_t start_watchdog(apr_a
     if (!wd->mds->nelts) {
         ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10065)
                      "no managed domain in state to drive, no watchdog needed, "
-                     "will check again on next server restart");
+                     "will check again on next server (graceful) restart");
         apr_pool_destroy(wd->p);
         return APR_SUCCESS;
     }

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=1806939&r1=1806938&r2=1806939&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_config.c (original)
+++ httpd/httpd/trunk/modules/md/mod_md_config.c Fri Sep  1 12:11:38 2017
@@ -25,6 +25,7 @@
 #include <http_vhost.h>
 
 #include "md.h"
+#include "md_crypt.h"
 #include "md_util.h"
 #include "mod_md_private.h"
 #include "mod_md_config.h"
@@ -39,6 +40,7 @@
 #define MD_CMD_MEMBER         "MDMember"
 #define MD_CMD_MEMBERS        "MDMembers"
 #define MD_CMD_PORTMAP        "MDPortMap"
+#define MD_CMD_PKEYS          "MDPrivateKeys"
 #define MD_CMD_RENEWWINDOW    "MDRenewWindow"
 #define MD_CMD_STOREDIR       "MDStoreDir"
 
@@ -65,8 +67,9 @@ static md_srv_conf_t defconf = {
     1,
     MD_DRIVE_AUTO,
     0,
-    apr_time_from_sec(14 * MD_SECS_PER_DAY),
-
+    NULL, 
+    apr_time_from_sec(90 * MD_SECS_PER_DAY), /* If the cert lifetime were 90 days, renew */
+    apr_time_from_sec(30 * MD_SECS_PER_DAY), /* 30 days before. Adjust to actual lifetime */
     MD_ACME_DEF_URL,
     "ACME",
     NULL,
@@ -109,6 +112,8 @@ static void srv_conf_props_clear(md_srv_
     sc->transitive = DEF_VAL;
     sc->drive_mode = DEF_VAL;
     sc->must_staple = DEF_VAL;
+    sc->pkey_spec = NULL;
+    sc->renew_norm = DEF_VAL;
     sc->renew_window = DEF_VAL;
     sc->ca_url = NULL;
     sc->ca_proto = NULL;
@@ -121,6 +126,8 @@ static void srv_conf_props_copy(md_srv_c
     to->transitive = from->transitive;
     to->drive_mode = from->drive_mode;
     to->must_staple = from->must_staple;
+    to->pkey_spec = from->pkey_spec;
+    to->renew_norm = from->renew_norm;
     to->renew_window = from->renew_window;
     to->ca_url = from->ca_url;
     to->ca_proto = from->ca_proto;
@@ -133,6 +140,8 @@ static void srv_conf_props_apply(md_t *m
     if (from->transitive != DEF_VAL) md->transitive = from->transitive;
     if (from->drive_mode != DEF_VAL) md->drive_mode = from->drive_mode;
     if (from->must_staple != DEF_VAL) md->must_staple = from->must_staple;
+    if (from->pkey_spec) md->pkey_spec = from->pkey_spec;
+    if (from->renew_norm != DEF_VAL) md->renew_norm = from->renew_norm;
     if (from->renew_window != DEF_VAL) md->renew_window = from->renew_window;
 
     if (from->ca_url) md->ca_url = from->ca_url;
@@ -166,6 +175,9 @@ static void *md_config_merge(apr_pool_t
 
     nsc->transitive = (add->transitive != DEF_VAL)? add->transitive : base->transitive;
     nsc->drive_mode = (add->drive_mode != DEF_VAL)? add->drive_mode : base->drive_mode;
+    nsc->must_staple = (add->must_staple != DEF_VAL)? add->must_staple : base->must_staple;
+    nsc->pkey_spec = add->pkey_spec? add->pkey_spec : base->pkey_spec;
+    nsc->renew_window = (add->renew_norm != DEF_VAL)? add->renew_norm : base->renew_norm;
     nsc->renew_window = (add->renew_window != DEF_VAL)? add->renew_window : base->renew_window;
 
     nsc->ca_url = add->ca_url? add->ca_url : base->ca_url;
@@ -242,7 +254,7 @@ static const char *md_config_sec_start(c
         return  MD_CMD_MD_SECTION "> directive missing closing '>'";
     }
 
-    arg = apr_pstrndup(cmd->pool, arg, endp-arg);
+    arg = apr_pstrndup(cmd->pool, arg, (apr_size_t)(endp-arg));
     if (!arg || !*arg) {
         return MD_CMD_MD_SECTION " > section must specify a unique domain name";
     }
@@ -444,23 +456,54 @@ static apr_status_t duration_parse(const
     return rv;
 }
 
+static apr_status_t percentage_parse(const char *value, int *ppercent)
+{
+    char *endp;
+    apr_int64_t n;
+    
+    n = apr_strtoi64(value, &endp, 10);
+    if (errno) {
+        return errno;
+    }
+    if (*endp == '%') {
+        if (n < 0 || n >= 100) {
+            return APR_BADARG;
+        }
+        *ppercent = (int)n;
+        return APR_SUCCESS;
+    }
+    return APR_EINVAL;
+}
+
 static const char *md_config_set_renew_window(cmd_parms *cmd, void *dc, const char *value)
 {
     md_srv_conf_t *config = md_config_get(cmd->server);
     const char *err;
     apr_interval_time_t timeout;
-
-    /* Inspired by http_core.c */
-    if (duration_parse(value, &timeout, "d") != APR_SUCCESS) {
-        return "MDRenewWindow has wrong format";
-    }
-        
+    int percent;
+    
     if (!inside_section(cmd, MD_CMD_MD_SECTION)
         && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
         return err;
     }
-    config->renew_window = timeout;
-    return NULL;
+
+    /* Inspired by http_core.c */
+    if (duration_parse(value, &timeout, "d") == APR_SUCCESS) {
+        config->renew_norm = 0;
+        config->renew_window = timeout;
+        return NULL;
+    }
+    else {
+        switch (percentage_parse(value, &percent)) {
+            case APR_SUCCESS:
+                config->renew_norm = 100;
+                config->renew_window = percent;
+                return NULL;
+            case APR_BADARG:
+                return "MDRenewWindow as percent must be less than 100";
+        }
+    }
+    return "MDRenewWindow has unrecognized format";
 }
 
 static const char *md_config_set_store_dir(cmd_parms *cmd, void *arg, const char *value)
@@ -555,6 +598,57 @@ static const char *md_config_set_cha_tye
     return NULL;
 }
 
+static const char *md_config_set_pkeys(cmd_parms *cmd, void *arg, 
+                                       int argc, char *const argv[])
+{
+    md_srv_conf_t *config = md_config_get(cmd->server);
+    const char *err, *ptype;
+    apr_int64_t bits;
+    
+    if (!inside_section(cmd, MD_CMD_MD_SECTION)
+        && (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
+        return err;
+    }
+    if (argc <= 0) {
+        return "needs to specify the private key type";
+    }
+    
+    ptype = argv[0];
+    if (!apr_strnatcasecmp("Default", ptype)) {
+        if (argc > 1) {
+            return "type 'Default' takes no parameter";
+        }
+        if (!config->pkey_spec) {
+            config->pkey_spec = apr_pcalloc(cmd->pool, sizeof(*config->pkey_spec));
+        }
+        config->pkey_spec->type = MD_PKEY_TYPE_DEFAULT;
+        return NULL;
+    }
+    else if (!apr_strnatcasecmp("RSA", ptype)) {
+        if (argc == 1) {
+            bits = MD_PKEY_RSA_BITS_DEF;
+        }
+        else if (argc == 2) {
+            bits = (int)apr_atoi64(argv[1]);
+            if (bits < 2048 || bits >= INT_MAX) {
+                return "must be a 2048 or higher in order to be considered safe. "
+                "Too large a value will slow down everything. Larger then 4096 probably does "
+                "not make sense unless quantum cryptography really changes spin.";
+            }
+        }
+        else {
+            return "key type 'RSA' has only one optinal parameter, the number of bits";
+        }
+
+        if (!config->pkey_spec) {
+            config->pkey_spec = apr_pcalloc(cmd->pool, sizeof(*config->pkey_spec));
+        }
+        config->pkey_spec->type = MD_PKEY_TYPE_RSA;
+        config->pkey_spec->params.rsa.bits = (unsigned int)bits;
+        return NULL;
+    }
+    return apr_pstrcat(cmd->pool, "unsupported private key type \"", ptype, "\"", NULL);
+}
 
 const command_rec md_cmds[] = {
     AP_INIT_TAKE1(     MD_CMD_CA, md_config_set_ca, NULL, RSRC_CONF, 
@@ -582,6 +676,8 @@ const command_rec md_cmds[] = {
                   "to indicate that the server port 8000 is reachable as port 80 from the "
                   "internet. Use 80:- to indicate that port 80 is not reachable from "
                   "the outside."),
+    AP_INIT_TAKE_ARGV( MD_CMD_PKEYS, md_config_set_pkeys, NULL, RSRC_CONF, 
+                  "set the type and parameters for private key generation"),
     AP_INIT_TAKE1(     MD_CMD_STOREDIR, md_config_set_store_dir, NULL, RSRC_CONF, 
                   "the directory for file system storage of managed domain data."),
     AP_INIT_TAKE1(     MD_CMD_RENEWWINDOW, md_config_set_renew_window, NULL, RSRC_CONF, 
@@ -654,6 +750,8 @@ int md_config_geti(const md_srv_conf_t *
 apr_interval_time_t md_config_get_interval(const md_srv_conf_t *sc, md_config_var_t var)
 {
     switch (var) {
+        case MD_CONFIG_RENEW_NORM:
+            return (sc->renew_norm != DEF_VAL)? sc->renew_norm : defconf.renew_norm;
         case MD_CONFIG_RENEW_WINDOW:
             return (sc->renew_window != DEF_VAL)? sc->renew_window : defconf.renew_window;
         default:

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=1806939&r1=1806938&r2=1806939&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_config.h (original)
+++ httpd/httpd/trunk/modules/md/mod_md_config.h Fri Sep  1 12:11:38 2017
@@ -17,6 +17,7 @@
 #define mod_md_md_config_h
 
 struct md_store_t;
+struct md_pkey_spec_t;
 
 typedef enum {
     MD_CONFIG_CA_URL,
@@ -26,6 +27,7 @@ typedef enum {
     MD_CONFIG_DRIVE_MODE,
     MD_CONFIG_LOCAL_80,
     MD_CONFIG_LOCAL_443,
+    MD_CONFIG_RENEW_NORM,
     MD_CONFIG_RENEW_WINDOW,
     MD_CONFIG_TRANSITIVE,
 } md_config_var_t;
@@ -51,6 +53,10 @@ typedef struct md_srv_conf_t {
     int transitive;                    /* != 0 iff VirtualHost names/aliases are auto-added */
     int drive_mode;                    /* mode of obtaining credentials */
     int must_staple;                   /* certificates should set the OCSP Must Staple extension */
+    struct md_pkey_spec_t *pkey_spec;  /* specification for generating private keys */
+    apr_interval_time_t renew_norm;    /* If > 0, use as normalizing value for cert lifetime
+                                        * Example: renew_norm=90d renew_win=30d, cert lives
+                                        * for 12 days => renewal 4 days before */
     apr_interval_time_t renew_window;  /* time before expiration that starts renewal */
     
     const char *ca_url;                /* url of CA certificate service */

Modified: httpd/httpd/trunk/modules/md/mod_md_os.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md_os.c?rev=1806939&r1=1806938&r2=1806939&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_os.c (original)
+++ httpd/httpd/trunk/modules/md/mod_md_os.c Fri Sep  1 12:11:38 2017
@@ -34,7 +34,7 @@
 #include "md_util.h"
 #include "mod_md_os.h"
 
-apr_status_t md_try_chown(const char *fname, int uid, int gid, apr_pool_t *p)
+apr_status_t md_try_chown(const char *fname, unsigned int uid, int gid, apr_pool_t *p)
 {
 #if AP_NEED_SET_MUTEX_PERMS
     if (-1 == chown(fname, (uid_t)uid, (gid_t)gid)) {

Modified: httpd/httpd/trunk/modules/md/mod_md_os.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/md/mod_md_os.h?rev=1806939&r1=1806938&r2=1806939&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/md/mod_md_os.h (original)
+++ httpd/httpd/trunk/modules/md/mod_md_os.h Fri Sep  1 12:11:38 2017
@@ -20,7 +20,7 @@
  * Try chown'ing the file/directory. Give id -1 to not change uid/gid.
  * Will return APR_ENOTIMPL on platforms not supporting this operation.
  */
-apr_status_t md_try_chown(const char *fname, int uid, int gid, apr_pool_t *p);
+apr_status_t md_try_chown(const char *fname, unsigned int uid, int gid, apr_pool_t *p);
 
 /**
  * Make a file or directory read/write(/searchable) by httpd workers.

Modified: httpd/httpd/trunk/modules/ssl/ssl_engine_init.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ssl/ssl_engine_init.c?rev=1806939&r1=1806938&r2=1806939&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/ssl/ssl_engine_init.c (original)
+++ httpd/httpd/trunk/modules/ssl/ssl_engine_init.c Fri Sep  1 12:11:38 2017
@@ -1723,8 +1723,9 @@ static apr_status_t ssl_init_server_ctx(
             else if (APR_STATUS_IS_EAGAIN(rv)) {
                 /* Managed Domain not ready yet. This is not a reason to fail the config */
                 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085)
-                             "Init: (%s) disabling this host for now as certificate/key data "
-                             "for the Managed Domain is incomplete.", ssl_util_vhostid(p, s));
+                             "Init: %s will respond with '503 Service Unavailable' for now. This "
+                             "host is part of a Managed Domain, but no SSL certificate is "
+                             "available (yet).", ssl_util_vhostid(p, s));
                 pks->service_unavailable = 1;
                 return APR_SUCCESS;
             }