httpd-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ic...@apache.org
Subject svn commit: r1816423 [2/5] - in /httpd/httpd/branches/2.4.x-mod_md: ./ docs/manual/ docs/manual/mod/ modules/md/ modules/ssl/
Date Mon, 27 Nov 2017 10:44:57 GMT
Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md.h?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md.h (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md.h Mon Nov 27 10:44:56 2017
@@ -24,18 +24,35 @@ struct md_json_t;
 struct md_cert_t;
 struct md_pkey_t;
 struct md_store_t;
+struct md_srv_conf_t;
+struct md_pkey_spec_t;
 
 #define MD_TLSSNI01_DNS_SUFFIX     ".acme.invalid"
 
+#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 */
     MD_S_COMPLETE,                  /* MD has all necessary information, can go live */
     MD_S_EXPIRED,                   /* MD is complete, but credentials have expired */
     MD_S_ERROR,                     /* MD data is flawed, unable to be processed as is */ 
+    MD_S_MISSING,                   /* MD is missing config information, cannot proceed */
 } md_state_t;
 
 typedef enum {
+    MD_REQUIRE_UNSET = -1,
+    MD_REQUIRE_OFF,
+    MD_REQUIRE_TEMPORARY,
+    MD_REQUIRE_PERMANENT,
+} md_require_t;
+
+typedef enum {
     MD_SV_TEXT,
     MD_SV_JSON,
     MD_SV_CERT,
@@ -64,30 +81,37 @@ typedef enum {
 typedef struct md_t md_t;
 struct md_t {
     const char *name;               /* unique name of this MD */
-    md_state_t state;               /* state of this MD */
-    apr_time_t expires;             /* When the credentials for this domain expire. 0 if unknown */
-    apr_interval_time_t renew_window;/* time before expiration that starts renewal */
-    
     struct apr_array_header_t *domains; /* all DNS names this MD includes */
+    struct apr_array_header_t *contacts;   /* list of contact uris, e.g. mailto:xxx */
+
     int transitive;                 /* != 0 iff VirtualHost names/aliases are auto-added */
-    md_drive_mode_t drive_mode;     /* mode of obtaining credentials */
+    md_require_t require_https;     /* Iff https: is required for this MD */
+    
+    int drive_mode;                 /* mode of obtaining credentials */
+    struct md_pkey_spec_t *pkey_spec;/* specification for generating new private keys */
     int must_staple;                /* certificates should set the OCSP Must Staple extension */
+    apr_interval_time_t renew_norm; /* if > 0, normalized cert lifetime */
+    apr_interval_time_t renew_window;/* time before expiration that starts renewal */
     
     const char *ca_url;             /* url of CA certificate service */
     const char *ca_proto;           /* protocol used vs CA (e.g. ACME) */
     const char *ca_account;         /* account used at CA */
     const char *ca_agreement;       /* accepted agreement uri between CA and user */ 
     struct apr_array_header_t *ca_challenges; /* challenge types configured for this MD */
-    struct apr_array_header_t *contacts;   /* list of contact uris, e.g. mailto:xxx */
 
+    md_state_t state;               /* state of this MD */
+    apr_time_t valid_from;          /* When the credentials start to be valid. 0 if unknown */
+    apr_time_t expires;             /* When the credentials expire. 0 if unknown */
     const char *cert_url;           /* url where cert has been created, remember during drive */ 
-
+    
+    const struct md_srv_conf_t *sc; /* server config where it was defined or NULL */
     const char *defn_name;          /* config file this MD was defined */
     unsigned defn_line_number;      /* line number of definition */
 };
 
 #define MD_KEY_ACCOUNT          "account"
 #define MD_KEY_AGREEMENT        "agreement"
+#define MD_KEY_BITS             "bits"
 #define MD_KEY_CA               "ca"
 #define MD_KEY_CA_URL           "ca-url"
 #define MD_KEY_CERT             "cert"
@@ -100,6 +124,7 @@ struct md_t {
 #define MD_KEY_DOMAIN           "domain"
 #define MD_KEY_DOMAINS          "domains"
 #define MD_KEY_DRIVE_MODE       "drive-mode"
+#define MD_KEY_ERRORS           "errors"
 #define MD_KEY_EXPIRES          "expires"
 #define MD_KEY_HTTP             "http"
 #define MD_KEY_HTTPS            "https"
@@ -108,37 +133,47 @@ struct md_t {
 #define MD_KEY_KEY              "key"
 #define MD_KEY_KEYAUTHZ         "keyAuthorization"
 #define MD_KEY_LOCATION         "location"
+#define MD_KEY_MUST_STAPLE      "must-staple"
 #define MD_KEY_NAME             "name"
+#define MD_KEY_PERMANENT        "permanent"
+#define MD_KEY_PKEY             "privkey"
+#define MD_KEY_PROCESSED        "processed"
 #define MD_KEY_PROTO            "proto"
 #define MD_KEY_REGISTRATION     "registration"
+#define MD_KEY_RENEW            "renew"
 #define MD_KEY_RENEW_WINDOW     "renew-window"
+#define MD_KEY_REQUIRE_HTTPS    "require-https"
 #define MD_KEY_RESOURCE         "resource"
 #define MD_KEY_STATE            "state"
 #define MD_KEY_STATUS           "status"
 #define MD_KEY_STORE            "store"
+#define MD_KEY_TEMPORARY        "temporary"
 #define MD_KEY_TOKEN            "token"
 #define MD_KEY_TRANSITIVE       "transitive"
 #define MD_KEY_TYPE             "type"
 #define MD_KEY_URL              "url"
 #define MD_KEY_URI              "uri"
+#define MD_KEY_VALID_FROM       "validFrom"
 #define MD_KEY_VALUE            "value"
 #define MD_KEY_VERSION          "version"
 
 #define MD_FN_MD                "md.json"
-#define MD_FN_PKEY              "pkey.pem"
+#define MD_FN_JOB               "job.json"
+#define MD_FN_PRIVKEY           "privkey.pem"
+#define MD_FN_PUBCERT           "pubcert.pem"
 #define MD_FN_CERT              "cert.pem"
 #define MD_FN_CHAIN             "chain.pem"
 #define MD_FN_HTTPD_JSON        "httpd.json"
 
+#define MD_FN_FALLBACK_PKEY     "fallback-privkey.pem"
+#define MD_FN_FALLBACK_CERT     "fallback-cert.pem"
+
 /* Check if a string member of a new MD (n) has 
  * a value and if it differs from the old MD o
  */
 #define MD_VAL_UPDATE(n,o,s)    ((n)->s != (o)->s)
 #define MD_SVAL_UPDATE(n,o,s)   ((n)->s && (!(o)->s || strcmp((n)->s, (o)->s)))
 
-#define MD_SECS_PER_HOUR      (60*60)
-#define MD_SECS_PER_DAY       (24*MD_SECS_PER_HOUR)
-
 /**
  * Determine if the Managed Domain contains a specific domain name.
  */
@@ -199,7 +234,7 @@ md_t *md_create_empty(apr_pool_t *p);
 /**
  * Create a managed domain, given a list of domain names.
  */
-const char *md_create(md_t **pmd, apr_pool_t *p, struct apr_array_header_t *domains);
+md_t *md_create(apr_pool_t *p, struct apr_array_header_t *domains);
 
 /**
  * Deep copy an md record into another pool.
@@ -211,6 +246,11 @@ md_t *md_clone(apr_pool_t *p, const md_t
  */
 md_t *md_copy(apr_pool_t *p, const md_t *src);
 
+/**
+ * Create a merged md with the settings of add overlaying the ones from base.
+ */
+md_t *md_merge(apr_pool_t *p, const md_t *add, const md_t *base);
+
 /** 
  * Convert the managed domain into a JSON representation and vice versa. 
  *
@@ -219,14 +259,19 @@ md_t *md_copy(apr_pool_t *p, const md_t
 struct md_json_t *md_to_json (const md_t *md, apr_pool_t *p);
 md_t *md_from_json(struct md_json_t *json, apr_pool_t *p);
 
+/**
+ * Determine if MD should renew its cert (if it has one)
+ */
+int md_should_renew(const md_t *md);
+
 /**************************************************************************************************/
 /* domain credentials */
 
 typedef struct md_creds_t md_creds_t;
 struct md_creds_t {
+    struct md_pkey_t *privkey;
+    struct apr_array_header_t *pubcert;    /* complete md_cert* chain */
     struct md_cert_t *cert;
-    struct md_pkey_t *pkey;
-    struct apr_array_header_t *chain;      /* list of md_cert* */
     int expired;
 };
 

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme.c?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme.c (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme.c Mon Nov 27 10:44:56 2017
@@ -67,7 +67,7 @@ static acme_problem_status_t Problems[]
 };
 
 static apr_status_t problem_status_get(const char *type) {
-    int i;
+    size_t i;
 
     if (strstr(type, "urn:ietf:params:") == type) {
         type += strlen("urn:ietf:params:");
@@ -90,7 +90,8 @@ apr_status_t md_acme_init(apr_pool_t *p,
     return md_crypt_init(p);
 }
 
-apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url)
+apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url,
+                            const char *proxy_url)
 {
     md_acme_t *acme;
     const char *err = NULL;
@@ -111,9 +112,9 @@ apr_status_t md_acme_create(md_acme_t **
     acme = apr_pcalloc(p, sizeof(*acme));
     acme->url = url;
     acme->p = p;
-    acme->user_agent = apr_psprintf(p, "%s mod_md/%s (Something, like certbot)", 
+    acme->user_agent = apr_psprintf(p, "%s mod_md/%s", 
                                     base_product, MOD_MD_VERSION);
-    acme->pkey_bits = 4096;
+    acme->proxy_url = proxy_url? apr_pstrdup(p, proxy_url) : NULL;
     acme->max_retries = 3;
     
     if (APR_SUCCESS != (rv = apr_uri_parse(p, url, &uri_parsed))) {
@@ -135,7 +136,7 @@ apr_status_t md_acme_setup(md_acme_t *ac
     
     assert(acme->url);
     if (!acme->http && APR_SUCCESS != (rv = md_http_create(&acme->http, acme->p,
-                                                           acme->user_agent))) {
+                                                           acme->user_agent, acme->proxy_url))) {
         return rv;
     }
     md_http_set_response_limit(acme->http, 1024*1024);
@@ -260,9 +261,15 @@ static apr_status_t inspect_problem(md_a
             ptype = md_json_gets(problem, "type", NULL); 
             pdetail = md_json_gets(problem, "detail", NULL);
             req->rv = problem_status_get(ptype);
-             
-            md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, req->rv, req->p,
-                          "acme problem %s: %s", ptype, pdetail);
+            
+            if (APR_STATUS_IS_EAGAIN(req->rv)) {
+                md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, req->rv, req->p,
+                              "acme reports %s: %s", ptype, pdetail);
+            }
+            else {
+                md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, req->rv, req->p,
+                              "acme problem %s: %s", ptype, pdetail);
+            }
             return req->rv;
         }
     }
@@ -277,7 +284,7 @@ static apr_status_t inspect_problem(md_a
                 return APR_ENOENT;
             default:
                 md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, req->p,
-                              "acme problem unknonw: http status %d", res->status);
+                              "acme problem unknown: http status %d", res->status);
                 return APR_EGENERAL;
         }
     }
@@ -485,7 +492,10 @@ static apr_status_t on_got_json(md_acme_
                                 md_json_t *jbody, void *baton)
 {
     json_ctx *ctx = baton;
-    
+
+    (void)acme;
+    (void)p;
+    (void)headers;
     ctx->json = md_json_clone(ctx->pool, jbody);
     return APR_SUCCESS;
 }

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme.h?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme.h (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme.h Mon Nov 27 10:44:56 2017
@@ -50,6 +50,7 @@ struct md_acme_t {
     const char *sname;              /* short name for the service, not necessarily unique */
     apr_pool_t *p;
     const char *user_agent;
+    const char *proxy_url;
     struct md_acme_acct_t *acct;
     struct md_pkey_t *acct_key;
     
@@ -62,7 +63,6 @@ struct md_acme_t {
     
     const char *nonce;
     int max_retries;
-    unsigned int pkey_bits;
 };
 
 /**
@@ -72,14 +72,16 @@ apr_status_t md_acme_init(apr_pool_t *po
 
 /**
  * Create a new ACME server instance. If path is not NULL, will use that directory
- * for persisting information. Will load any inforation persisted in earlier session.
+ * for persisting information. Will load any information persisted in earlier session.
  * url needs only be specified for instances where this has never been persisted before.
  *
  * @param pacme   will hold the ACME server instance on success
  * @param p       pool to used
  * @param url     url of the server, optional if known at path
+ * @param proxy_url optional url of a HTTP(S) proxy to use
  */
-apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url);
+apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url,
+                            const char *proxy_url);
 
 /**
  * Contact the ACME server and retrieve its directory information.
@@ -111,7 +113,7 @@ apr_status_t md_acme_use_acct_staged(md_
  * Get the local name of the account currently used by the acme instance.
  * Will be NULL if no account has been setup successfully.
  */
-const char *md_acme_get_acct(md_acme_t *acme, apr_pool_t *p);
+const char *md_acme_get_acct_id(md_acme_t *acme);
 
 /**
  * Agree to the given Terms-of-Service url for the current account.
@@ -123,11 +125,15 @@ apr_status_t md_acme_agree(md_acme_t *ac
  * given in the agreement url.
  * If the known agreement is equal to this, nothing is done.
  * If it differs, the account is re-validated in the hope that the server
- * accounces the Tos URL it wants. If this is equal to the agreement specified,
+ * announces the Tos URL it wants. If this is equal to the agreement specified,
  * the server is notified of this. If the server requires a ToS that the account
  * thinks it has already given, it is resend.
+ *
+ * If an agreement is required, different from the current one, APR_INCOMPLETE is
+ * returned and the agreement url is returned in the parameter.
  */
-apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p, const char *agreement);
+apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p, 
+                                     const char *agreement, const char **prequired);
 
 /**
  * Get the ToS agreement for current account.
@@ -170,7 +176,7 @@ apr_status_t md_acme_unstore_acct(struct
 /* request handling */
 
 /**
- * Request callback on a successfull HTTP response (status 2xx).
+ * Request callback on a successful HTTP response (status 2xx).
  */
 typedef apr_status_t md_acme_req_res_cb(md_acme_t *acme, 
                                         const struct md_http_response_t *res, void *baton);
@@ -187,7 +193,7 @@ typedef struct md_acme_req_t md_acme_req
 typedef apr_status_t md_acme_req_init_cb(md_acme_req_t *req, void *baton);
 
 /**
- * Request callback on a successfull response (HTTP response code 2xx) and content
+ * Request callback on a successful response (HTTP response code 2xx) and content
  * type matching application/.*json.
  */
 typedef apr_status_t md_acme_req_json_cb(md_acme_t *acme, apr_pool_t *p, 
@@ -204,7 +210,7 @@ struct md_acme_req_t {
     struct md_json_t *req_json;    /* JSON to be POSTed in request body */
 
     apr_table_t *resp_hdrs;        /* HTTP response headers */
-    struct md_json_t *resp_json;   /* JSON response body recevied */
+    struct md_json_t *resp_json;   /* JSON response body received */
     
     apr_status_t rv;               /* status of request */
     

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_acct.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_acct.c?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_acct.c (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_acct.c Mon Nov 27 10:44:56 2017
@@ -58,10 +58,6 @@ static apr_status_t acct_make(md_acme_ac
 }
 
 
-static void md_acme_acct_free(md_acme_acct_t *acct)
-{
-}
-
 static const char *mk_acct_id(apr_pool_t *p, md_acme_t *acme, int i)
 {
     return apr_psprintf(p, "ACME-%s-%04d", acme->sname, i);
@@ -225,20 +221,25 @@ static int find_acct(void *baton, const
                      md_store_vtype_t vtype, void *value, apr_pool_t *ptemp)
 {
     find_ctx *ctx = baton;
-    md_json_t *json = value;
     int disabled;
     const char *ca_url, *id;
     
-    id = md_json_gets(json, MD_KEY_ID, NULL);
-    disabled = md_json_getb(json, MD_KEY_DISABLED, NULL);
-    ca_url = md_json_gets(json, MD_KEY_CA_URL, NULL);
-    
-    if (!disabled && ca_url && !strcmp(ctx->acme->url, ca_url)) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ctx->p, 
-                      "found account %s for %s: %s, disabled=%d, ca-url=%s", 
-                      name, ctx->acme->url, id, disabled, ca_url);
-        ctx->id = id;
-        return 0;
+    (void)aspect;
+    (void)ptemp;
+    if (MD_SV_JSON == vtype) {
+        md_json_t *json = value;
+        
+        id = md_json_gets(json, MD_KEY_ID, NULL);
+        disabled = md_json_getb(json, MD_KEY_DISABLED, NULL);
+        ca_url = md_json_gets(json, MD_KEY_CA_URL, NULL);
+        
+        if (!disabled && ca_url && !strcmp(ctx->acme->url, ca_url)) {
+            md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ctx->p, 
+                          "found account %s for %s: %s, disabled=%d, ca-url=%s", 
+                          name, ctx->acme->url, id, disabled, ca_url);
+            ctx->id = id;
+            return 0;
+        }
     }
     return 1;
 }
@@ -327,6 +328,7 @@ static apr_status_t acct_register(md_acm
     apr_status_t rv;
     md_pkey_t *pkey;
     const char *err = NULL, *uri;
+    md_pkey_spec_t spec;
     int i;
     
     md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "create new account");
@@ -347,7 +349,10 @@ static apr_status_t acct_register(md_acm
         }
     }
     
-    if (APR_SUCCESS == (rv = md_pkey_gen_rsa(&pkey, acme->p, acme->pkey_bits))
+    spec.type = MD_PKEY_TYPE_RSA;
+    spec.params.rsa.bits = MD_ACME_ACCT_PKEY_BITS;
+    
+    if (APR_SUCCESS == (rv = md_pkey_gen(&pkey, acme->p, &spec))
         && APR_SUCCESS == (rv = acct_make(&acme->acct,  p, acme->url, NULL, contacts))) {
         acct_ctx_t ctx;
 
@@ -367,7 +372,6 @@ static apr_status_t acct_register(md_acm
 
 out:    
     if (APR_SUCCESS != rv && acme->acct) {
-        md_acme_acct_free(acme->acct);
         acme->acct = NULL;
     }
     return rv;
@@ -380,6 +384,7 @@ static apr_status_t on_init_acct_valid(m
 {
     md_json_t *jpayload;
 
+    (void)baton;
     jpayload = md_json_create(req->p);
     md_json_sets("reg", jpayload, MD_KEY_RESOURCE, NULL);
     
@@ -394,6 +399,8 @@ static apr_status_t acct_valid(md_acme_t
     const char *body_str;
     const char *tos_required;
     
+    (void)p;
+    (void)baton;
     apr_array_clear(acct->contacts);
     md_json_getsa(acct->contacts, body, MD_KEY_CONTACT, NULL);
     acct->registration = md_json_clone(acme->p, body);
@@ -489,7 +496,7 @@ apr_status_t md_acme_use_acct_staged(md_
     return rv;
 }
 
-const char *md_acme_get_acct(md_acme_t *acme, apr_pool_t *p)
+const char *md_acme_get_acct_id(md_acme_t *acme)
 {
     return acme->acct? acme->acct->id : NULL;
 }
@@ -549,6 +556,7 @@ static apr_status_t on_init_acct_del(md_
 {
     md_json_t *jpayload;
 
+    (void)baton;
     jpayload = md_json_create(req->p);
     md_json_sets("reg", jpayload, MD_KEY_RESOURCE, NULL);
     md_json_setb(1, jpayload, "delete", NULL);
@@ -561,7 +569,9 @@ static apr_status_t acct_del(md_acme_t *
 {
     md_store_t *store = baton;
     apr_status_t rv = APR_SUCCESS;
-    
+
+    (void)hdrs;
+    (void)body;
     md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, p, "deleted account %s", acme->acct->url);
     if (store) {
         rv = md_acme_unstore_acct(store, p, acme->acct->id);
@@ -575,6 +585,7 @@ apr_status_t md_acme_delete_acct(md_acme
 {
     md_acme_acct_t *acct = acme->acct;
     
+    (void)p;
     if (!acct) {
         return APR_EINVAL;
     }
@@ -610,15 +621,23 @@ apr_status_t md_acme_agree(md_acme_t *ac
 
 static int agreement_required(md_acme_acct_t *acct)
 {
-    return (!acct->agreement 
-            || (acct->tos_required && strcmp(acct->tos_required, acct->agreement)));
+    /* We used to really check if the account agreement and the one
+     * indicated as valid are the very same:
+     * return (!acct->agreement 
+     *       || (acct->tos_required && strcmp(acct->tos_required, acct->agreement)));
+     * However, LE is happy if the account has agreed to a ToS in the past and
+     * does not required a renewed acceptance.
+     */
+     return !acct->agreement; 
 }
 
-apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p, const char *agreement)
+apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p, 
+                                     const char *agreement, const char **prequired)
 {
     apr_status_t rv = APR_SUCCESS;
     
     /* Check if (correct) Terms-of-Service for account were accepted */
+    *prequired = NULL;
     if (agreement_required(acme->acct)) {
         const char *tos = acme->acct->tos_required;
         if (!tos) {
@@ -642,10 +661,8 @@ apr_status_t md_acme_check_agreement(md_
             rv = md_acme_agree(acme, p, tos);
         }
         else {
-            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, acme->p, 
-                          "need to accept terms-of-service <%s> for account %s", 
-                          tos, acme->acct->id);
-            rv = APR_EACCES;
+            *prequired = apr_pstrdup(p, tos);
+            rv = APR_INCOMPLETE;
         }
     }
     return rv;

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_acct.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_acct.h?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_acct.h (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_acct.h Mon Nov 27 10:44:56 2017
@@ -41,4 +41,8 @@ struct md_acme_acct_t {
 #define MD_FN_ACCOUNT           "account.json"
 #define MD_FN_ACCT_KEY          "account.pem"
 
+/* ACME account private keys are always RSA and have that many bits. Since accounts
+ * are expected to live long, better err on the safe side. */
+#define MD_ACME_ACCT_PKEY_BITS  3072
+
 #endif /* md_acme_acct_h */

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_authz.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_authz.c?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_authz.c (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_authz.c Mon Nov 27 10:44:56 2017
@@ -45,7 +45,7 @@ md_acme_authz_t *md_acme_authz_create(ap
     return authz;
 }
 
-md_acme_authz_set_t *md_acme_authz_set_create(apr_pool_t *p, md_acme_t *acme)
+md_acme_authz_set_t *md_acme_authz_set_create(apr_pool_t *p)
 {
     md_acme_authz_set_t *authz_set;
     
@@ -91,10 +91,10 @@ apr_status_t md_acme_authz_set_remove(md
     for (i = 0; i < set->authzs->nelts; ++i) {
         authz = APR_ARRAY_IDX(set->authzs, i, md_acme_authz_t *);
         if (!apr_strnatcasecmp(domain, authz->domain)) {
-            int n = i +1;
+            int n = i + 1;
             if (n < set->authzs->nelts) {
                 void **elems = (void **)set->authzs->elts;
-                memmove(elems + i, elems + n, set->authzs->nelts - n); 
+                memmove(elems + i, elems + n, (size_t)(set->authzs->nelts - n)); 
             }
             --set->authzs->nelts;
             return APR_SUCCESS;
@@ -152,6 +152,8 @@ static apr_status_t authz_created(md_acm
     const char *location = apr_table_get(hdrs, "location");
     apr_status_t rv = APR_SUCCESS;
     
+    (void)acme;
+    (void)p;
     if (location) {
         ctx->authz = md_acme_authz_create(ctx->p);
         ctx->authz->domain = apr_pstrdup(ctx->p, ctx->domain);
@@ -172,6 +174,7 @@ apr_status_t md_acme_authz_register(stru
     apr_status_t rv;
     authz_req_ctx ctx;
     
+    (void)store;
     authz_req_ctx_init(&ctx, acme, domain, NULL, p);
     
     md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, acme->p, "create new authz");
@@ -182,7 +185,7 @@ apr_status_t md_acme_authz_register(stru
 }
 
 /**************************************************************************************************/
-/* Update an exiosting authorization */
+/* Update an existing authorization */
 
 apr_status_t md_acme_authz_update(md_acme_authz_t *authz, md_acme_t *acme, 
                                   md_store_t *store, apr_pool_t *p)
@@ -191,6 +194,7 @@ apr_status_t md_acme_authz_update(md_acm
     const char *s;
     apr_status_t rv;
     
+    (void)store;
     assert(acme);
     assert(acme->http);
     assert(authz);
@@ -261,6 +265,10 @@ static apr_status_t authz_http_set(md_ac
 {
     authz_req_ctx *ctx = baton;
     
+    (void)acme;
+    (void)p;
+    (void)hdrs;
+    (void)body;
     md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, ctx->p, "updated authz %s", ctx->authz->location);
     return APR_SUCCESS;
 }
@@ -271,6 +279,7 @@ static apr_status_t setup_key_authz(md_a
     const char *thumb64, *key_authz;
     apr_status_t rv;
     
+    (void)authz;
     assert(cha);
     assert(cha->token);
     
@@ -292,12 +301,14 @@ static apr_status_t setup_key_authz(md_a
 }
 
 static apr_status_t cha_http_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *authz, 
-                                      md_acme_t *acme, md_store_t *store, apr_pool_t *p)
+                                      md_acme_t *acme, md_store_t *store, 
+                                      md_pkey_spec_t *key_spec, apr_pool_t *p)
 {
     const char *data;
     apr_status_t rv;
     int notify_server;
     
+    (void)key_spec;
     if (APR_SUCCESS != (rv = setup_key_authz(cha, authz, acme, p, &notify_server))) {
         goto out;
     }
@@ -347,13 +358,15 @@ static apr_status_t setup_cha_dns(const
 }
 
 static apr_status_t cha_tls_sni_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *authz, 
-                                         md_acme_t *acme, md_store_t *store, apr_pool_t *p)
+                                         md_acme_t *acme, md_store_t *store, 
+                                         md_pkey_spec_t *key_spec, apr_pool_t *p)
 {
     md_cert_t *cha_cert;
     md_pkey_t *cha_key;
     const char *cha_dns;
     apr_status_t rv;
     int notify_server;
+    apr_array_header_t *domains;
     
     if (   APR_SUCCESS != (rv = setup_key_authz(cha, authz, acme, p, &notify_server))
         || APR_SUCCESS != (rv = setup_cha_dns(&cha_dns, cha, p))) {
@@ -365,14 +378,16 @@ static apr_status_t cha_tls_sni_01_setup
     if ((APR_SUCCESS == rv && !md_cert_covers_domain(cha_cert, cha_dns)) 
         || APR_STATUS_IS_ENOENT(rv)) {
         
-        if (APR_SUCCESS != (rv = md_pkey_gen_rsa(&cha_key, p, acme->pkey_bits))) {
-            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: create tls-sni-01 challgenge key",
+        if (APR_SUCCESS != (rv = md_pkey_gen(&cha_key, p, key_spec))) {
+            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: create tls-sni-01 challenge key",
                           authz->domain);
             goto out;
         }
 
         /* setup a certificate containing the challenge dns */
-        rv = md_cert_self_sign(&cha_cert, authz->domain, cha_dns, cha_key, 
+        domains = apr_array_make(p, 5, sizeof(const char*));
+        APR_ARRAY_PUSH(domains, const char*) = cha_dns;
+        rv = md_cert_self_sign(&cha_cert, authz->domain, domains, cha_key, 
                                apr_time_from_sec(7 * MD_SECS_PER_DAY), p);
         
         if (APR_SUCCESS != rv) {
@@ -405,7 +420,8 @@ out:
 }
 
 typedef apr_status_t cha_starter(md_acme_authz_cha_t *cha, md_acme_authz_t *authz, 
-                                 md_acme_t *acme, md_store_t *store, apr_pool_t *p);
+                                 md_acme_t *acme, md_store_t *store, 
+                                 md_pkey_spec_t *key_spec, apr_pool_t *p);
                                  
 typedef struct {
     const char *name;
@@ -428,9 +444,10 @@ typedef struct {
 static apr_status_t collect_offered(void *baton, size_t index, md_json_t *json)
 {
     cha_find_ctx *ctx = baton;
+    const char *ctype;
     
-    const char *ctype = md_json_gets(json, MD_KEY_TYPE, NULL);
-    if (ctype) {
+    (void)index;
+    if ((ctype = md_json_gets(json, MD_KEY_TYPE, NULL))) {
         APR_ARRAY_PUSH(ctx->offered, const char*) = apr_pstrdup(ctx->p, ctype);
     }
     return 1;
@@ -449,7 +466,8 @@ static apr_status_t find_type(void *bato
 }
 
 apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, md_acme_t *acme, md_store_t *store, 
-                                   apr_array_header_t *challenges, apr_pool_t *p)
+                                   apr_array_header_t *challenges, 
+                                   md_pkey_spec_t *key_spec, apr_pool_t *p)
 {
     apr_status_t rv;
     int i;
@@ -483,9 +501,9 @@ apr_status_t md_acme_authz_respond(md_ac
         return rv;
     }
     
-    for (i = 0; i < CHA_TYPES_LEN; ++i) {
+    for (i = 0; i < (int)CHA_TYPES_LEN; ++i) {
         if (!apr_strnatcasecmp(CHA_TYPES[i].name, fctx.accepted->type)) {
-            return CHA_TYPES[i].start(fctx.accepted, authz, acme, store, p);
+            return CHA_TYPES[i].start(fctx.accepted, authz, acme, store, key_spec, p);
         }
     }
     
@@ -508,6 +526,7 @@ static apr_status_t on_init_authz_del(md
 {
     md_json_t *jpayload;
 
+    (void)baton;
     jpayload = md_json_create(req->p);
     md_json_sets("deactivated", jpayload, MD_KEY_STATUS, NULL);
     
@@ -519,6 +538,9 @@ static apr_status_t authz_del(md_acme_t
 {
     authz_req_ctx *ctx = baton;
     
+    (void)p;
+    (void)body;
+    (void)hdrs;
     md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, ctx->p, "deleted authz %s", ctx->authz->location);
     acme->acct = NULL;
     return APR_SUCCESS;
@@ -529,6 +551,7 @@ apr_status_t md_acme_authz_del(md_acme_a
 {
     authz_req_ctx ctx;
     
+    (void)store;
     ctx.p = p;
     ctx.authz = authz;
     
@@ -560,7 +583,7 @@ md_acme_authz_t *md_acme_authz_from_json
         authz->domain = md_json_dups(p, json, MD_KEY_DOMAIN, NULL);            
         authz->location = md_json_dups(p, json, MD_KEY_LOCATION, NULL);            
         authz->dir = md_json_dups(p, json, MD_KEY_DIR, NULL);            
-        authz->state = (int)md_json_getl(json, MD_KEY_STATE, NULL);            
+        authz->state = (md_acme_authz_state_t)md_json_getl(json, MD_KEY_STATE, NULL);            
         return authz;
     }
     return NULL;
@@ -574,11 +597,13 @@ md_acme_authz_t *md_acme_authz_from_json
 
 static apr_status_t authz_to_json(void *value, md_json_t *json, apr_pool_t *p, void *baton)
 {
+    (void)baton;
     return md_json_setj(md_acme_authz_to_json(value, p), json, NULL);
 }
 
 static apr_status_t authz_from_json(void **pvalue, md_json_t *json, apr_pool_t *p, void *baton)
 {
+    (void)baton;
     *pvalue = md_acme_authz_from_json(json, p);
     return (*pvalue)? APR_SUCCESS : APR_EINVAL;
 }
@@ -595,7 +620,7 @@ md_json_t *md_acme_authz_set_to_json(md_
 
 md_acme_authz_set_t *md_acme_authz_set_from_json(md_json_t *json, apr_pool_t *p)
 {
-    md_acme_authz_set_t *set = md_acme_authz_set_create(p, NULL);
+    md_acme_authz_set_t *set = md_acme_authz_set_create(p);
     if (set) {
         md_json_geta(set->authzs, authz_from_json, NULL, json, MD_KEY_AUTHZS, NULL);
         return set;
@@ -630,8 +655,9 @@ static apr_status_t p_save(void *baton,
     md_acme_authz_set_t *set;
     const char *md_name;
     int create;
-    
-    group = va_arg(ap, int);
+ 
+    (void)p;   
+    group = (md_store_group_t)va_arg(ap, int);
     md_name = va_arg(ap, const char *);
     set = va_arg(ap, md_acme_authz_set_t *);
     create = va_arg(ap, int);
@@ -657,7 +683,7 @@ static apr_status_t p_purge(void *baton,
     const char *md_name;
     int i;
 
-    group = va_arg(ap, int);
+    group = (md_store_group_t)va_arg(ap, int);
     md_name = va_arg(ap, const char *);
 
     if (APR_SUCCESS == md_acme_authz_set_load(store, group, md_name, &authz_set, p)) {

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_authz.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_authz.h?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_authz.h (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_authz.h Mon Nov 27 10:44:56 2017
@@ -21,6 +21,7 @@ struct md_acme_t;
 struct md_acme_acct_t;
 struct md_json_t;
 struct md_store_t;
+struct md_pkey_spec_t;
 
 typedef struct md_acme_challenge_t md_acme_challenge_t;
 
@@ -67,8 +68,8 @@ apr_status_t md_acme_authz_update(md_acm
                                   struct md_store_t *store, apr_pool_t *p);
 
 apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, struct md_acme_t *acme, 
-                                   struct md_store_t *store, 
-                                   apr_array_header_t *challenges, apr_pool_t *p);
+                                   struct md_store_t *store, apr_array_header_t *challenges, 
+                                   struct md_pkey_spec_t *key_spec, apr_pool_t *p);
 apr_status_t md_acme_authz_del(md_acme_authz_t *authz, struct md_acme_t *acme, 
                                struct md_store_t *store, apr_pool_t *p);
 
@@ -81,7 +82,7 @@ struct md_acme_authz_set_t {
     struct apr_array_header_t *authzs;
 };
 
-md_acme_authz_set_t *md_acme_authz_set_create(apr_pool_t *p, struct md_acme_t *acme);
+md_acme_authz_set_t *md_acme_authz_set_create(apr_pool_t *p);
 md_acme_authz_t *md_acme_authz_set_get(md_acme_authz_set_t *set, const char *domain);
 apr_status_t md_acme_authz_set_add(md_acme_authz_set_t *set, md_acme_authz_t *authz);
 apr_status_t md_acme_authz_set_remove(md_acme_authz_set_t *set, const char *domain);

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_drive.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_drive.c?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_drive.c (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_acme_drive.c Mon Nov 27 10:44:56 2017
@@ -42,9 +42,11 @@ typedef struct {
     const char *phase;
     int complete;
 
-    md_pkey_t *pkey;
-    md_cert_t *cert;
-    apr_array_header_t *chain;
+    md_pkey_t *privkey;              /* the new private key */
+    apr_array_header_t *pubcert;     /* the new certificate + chain certs */
+    
+    md_cert_t *cert;                 /* the new certificate */
+    apr_array_header_t *chain;       /* the chain certificates */
 
     md_acme_t *acme;
     md_t *md;
@@ -73,7 +75,7 @@ static apr_status_t ad_set_acct(md_proto
     
     ad->phase = "setup acme";
     if (!ad->acme 
-        && APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, md->ca_url))) {
+        && APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, md->ca_url, d->proxy_url))) {
         goto out;
     }
 
@@ -105,7 +107,7 @@ static apr_status_t ad_set_acct(md_proto
         md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: looking at existing accounts",
                       d->proto->protocol);
         if (APR_SUCCESS == md_acme_find_acct(ad->acme, d->store, d->p)) {
-            md->ca_account = md_acme_get_acct(ad->acme, d->p);
+            md->ca_account = md_acme_get_acct_id(ad->acme);
             update = 1;
         }
     }
@@ -122,8 +124,8 @@ static apr_status_t ad_set_acct(md_proto
             goto out;
         }
     
-        if (APR_SUCCESS == (rv = md_acme_create_acct(ad->acme, d->p, 
-                                                     md->contacts, md->ca_agreement))
+        if (APR_SUCCESS == (rv = md_acme_create_acct(ad->acme, d->p, md->contacts, 
+                                                     md->ca_agreement))
             && APR_SUCCESS == (rv = md_acme_acct_save_staged(ad->acme, d->store, md, d->p))) {
             md->ca_account = MD_ACME_ACCT_STAGED;
             update = 1;
@@ -134,7 +136,7 @@ out:
     if (APR_SUCCESS == rv) {
         const char *agreement = md_acme_get_agreement(ad->acme);
         /* Persist the account chosen at the md so we use the same on future runs */
-        if (agreement && (!md->ca_agreement || strcmp(agreement, md->ca_agreement))) { 
+        if (agreement && !md->ca_agreement) { 
             md->ca_agreement = agreement;
             update = 1;
         }
@@ -174,7 +176,7 @@ static apr_status_t ad_setup_authz(md_pr
      */
     rv = md_acme_authz_set_load(d->store, MD_SG_STAGING, md->name, &ad->authz_set, d->p);
     if (!ad->authz_set || APR_STATUS_IS_ENOENT(rv)) {
-        ad->authz_set = md_acme_authz_set_create(d->p, ad->acme);
+        ad->authz_set = md_acme_authz_set_create(d->p);
         rv = APR_SUCCESS;
     }
     else if (APR_SUCCESS != rv) {
@@ -267,11 +269,13 @@ static apr_status_t ad_start_challenges(
         switch (authz->state) {
             case MD_ACME_AUTHZ_S_VALID:
                 break;
-            case MD_ACME_AUTHZ_S_PENDING:
                 
-                rv = md_acme_authz_respond(authz, ad->acme, d->store, ad->ca_challenges, d->p);
+            case MD_ACME_AUTHZ_S_PENDING:
+                rv = md_acme_authz_respond(authz, ad->acme, d->store, ad->ca_challenges, 
+                                           d->md->pkey_spec, d->p);
                 changed = 1;
                 break;
+                
             default:
                 rv = APR_EINVAL;
                 md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p, 
@@ -288,7 +292,7 @@ static apr_status_t ad_start_challenges(
     return rv;
 }
 
-static apr_status_t check_challenges(void *baton, int attemmpt)
+static apr_status_t check_challenges(void *baton, int attempt)
 {
     md_proto_driver_t *d = baton;
     md_acme_driver_t *ad = d->baton;
@@ -298,8 +302,8 @@ static apr_status_t check_challenges(voi
     
     for (i = 0; i < ad->authz_set->authzs->nelts && APR_SUCCESS == rv; ++i) {
         authz = APR_ARRAY_IDX(ad->authz_set->authzs, i, md_acme_authz_t*);
-        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: check AUTHZ for %s", 
-                      ad->md->name, authz->domain);
+        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: check AUTHZ for %s(%d. attempt)", 
+                      ad->md->name, authz->domain, attempt);
         if (APR_SUCCESS == (rv = md_acme_authz_update(authz, ad->acme, d->store, d->p))) {
             switch (authz->state) {
                 case MD_ACME_AUTHZ_S_VALID:
@@ -362,7 +366,7 @@ static apr_status_t on_got_cert(md_acme_
     md_acme_driver_t *ad = d->baton;
     apr_status_t rv = APR_SUCCESS;
     
-    
+    (void)acme;
     if (APR_SUCCESS == (rv = read_http_cert(&ad->cert, d->p, res))) {
         rv = md_store_save(d->store, d->p, MD_SG_STAGING, ad->md->name, MD_FN_CERT, 
                            MD_SV_CERT, ad->cert, 0);
@@ -376,6 +380,7 @@ static apr_status_t get_cert(void *baton
     md_proto_driver_t *d = baton;
     md_acme_driver_t *ad = d->baton;
     
+    (void)attempt;
     return md_acme_GET(ad->acme, ad->md->cert_url, NULL, NULL, on_got_cert, d);
 }
 
@@ -422,6 +427,7 @@ static apr_status_t csr_req(md_acme_t *a
     md_acme_driver_t *ad = d->baton;
     apr_status_t rv = APR_SUCCESS;
     
+    (void)acme;
     ad->md->cert_url = apr_table_get(res->headers, "location");
     if (!ad->md->cert_url) {
         md_log_perror(MD_LOG_MARK, MD_LOG_ERR, APR_EINVAL, d->p, 
@@ -464,22 +470,22 @@ static apr_status_t csr_req(md_acme_t *a
 static apr_status_t ad_setup_certificate(md_proto_driver_t *d)
 {
     md_acme_driver_t *ad = d->baton;
-    md_pkey_t *pkey;
+    md_pkey_t *privkey;
     apr_status_t rv;
 
-    ad->phase = "setup cert pkey";
+    ad->phase = "setup cert privkey";
     
-    rv = md_pkey_load(d->store, MD_SG_STAGING, ad->md->name, &pkey, d->p);
+    rv = md_pkey_load(d->store, MD_SG_STAGING, ad->md->name, &privkey, d->p);
     if (APR_STATUS_IS_ENOENT(rv)) {
-        if (APR_SUCCESS == (rv = md_pkey_gen_rsa(&pkey, d->p, ad->acme->pkey_bits))) {
-            rv = md_pkey_save(d->store, d->p, MD_SG_STAGING, ad->md->name, pkey, 1);
+        if (APR_SUCCESS == (rv = md_pkey_gen(&privkey, d->p, d->md->pkey_spec))) {
+            rv = md_pkey_save(d->store, d->p, MD_SG_STAGING, ad->md->name, privkey, 1);
         }
-        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: generate pkey", ad->md->name);
+        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: generate privkey", ad->md->name);
     }
 
     if (APR_SUCCESS == rv) {
         ad->phase = "setup csr";
-        rv = md_cert_req_create(&ad->csr_der_64, ad->md, pkey, d->p);
+        rv = md_cert_req_create(&ad->csr_der_64, ad->md, privkey, d->p);
         md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: create CSR", ad->md->name);
     }
 
@@ -507,6 +513,7 @@ static apr_status_t on_add_chain(md_acme
     md_cert_t *cert;
     const char *ct;
     
+    (void)acme;
     ct = apr_table_get(res->headers, "Content-Type");
     if (ct && !strcmp("application/x-pkcs7-mime", ct)) {
         /* root cert most likely, end it here */
@@ -527,7 +534,7 @@ static apr_status_t get_chain(void *bato
     md_cert_t *cert;
     const char *url, *last_url = NULL;
     apr_status_t rv = APR_SUCCESS;
-    
+
     while (APR_SUCCESS == rv && ad->chain->nelts < 10) {
         int nelts = ad->chain->nelts;
         if (ad->chain && nelts > 0) {
@@ -565,7 +572,7 @@ static apr_status_t get_chain(void *bato
         }
     }
     md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, rv, d->p, 
-                  "got chain with %d certs", ad->chain->nelts);
+                  "got chain with %d certs (%d. attempt)", ad->chain->nelts, attempt);
     return rv;
 }
 
@@ -613,8 +620,8 @@ static apr_status_t acme_driver_init(md_
     }
     else {
         /* free to chose. Add all we support and see what we get offered */
-        APR_ARRAY_PUSH(ad->ca_challenges, const char*) = MD_AUTHZ_TYPE_TLSSNI01;
         APR_ARRAY_PUSH(ad->ca_challenges, const char*) = MD_AUTHZ_TYPE_HTTP01;
+        APR_ARRAY_PUSH(ad->ca_challenges, const char*) = MD_AUTHZ_TYPE_TLSSNI01;
     }
     
     if (!d->can_http && !d->can_https) {
@@ -625,6 +632,21 @@ static apr_status_t acme_driver_init(md_
         return APR_EGENERAL;
     }
     
+    if (!d->can_http) {
+        ad->ca_challenges = md_array_str_remove(d->p, ad->ca_challenges, MD_AUTHZ_TYPE_HTTP01, 0);
+    }
+    if (!d->can_https) {
+        ad->ca_challenges = md_array_str_remove(d->p, ad->ca_challenges, MD_AUTHZ_TYPE_TLSSNI01, 0);
+    }
+
+    if (apr_is_empty_array(ad->ca_challenges)) {
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, d->p, "%s: specific CA challenge methods "
+                      "have been configured, but the server is unable to use any of those. "
+                      "For 'http-01' it needs to be reachable on port 80, for 'tls-sni-01'"
+                      " port 443 is needed.", d->md->name);
+        return APR_EGENERAL;
+    }
+    
     md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, d->p, "%s: init driver", d->md->name);
     
     return rv;
@@ -651,7 +673,7 @@ static apr_status_t acme_stage(md_proto_
         rv = md_load(d->store, MD_SG_STAGING, d->md->name, &ad->md, d->p);
         if (APR_SUCCESS == rv) {
             /* So, we have a copy in staging, but is it a recent or an old one? */
-            if (!md_is_newer(d->store, MD_SG_STAGING, MD_SG_DOMAINS, d->md->name, d->p)) {
+            if (md_is_newer(d->store, MD_SG_DOMAINS, MD_SG_STAGING, d->md->name, d->p)) {
                 reset_staging = 1;
             }
         }
@@ -674,6 +696,12 @@ static apr_status_t acme_stage(md_proto_
         ad->md = NULL;
     }
     
+    if (ad->md && ad->md->state == MD_S_MISSING) {
+        /* There is config information missing. It makes no sense to drive this MD further */
+        rv = APR_INCOMPLETE;
+        goto out;
+    }
+    
     if (ad->md) {
         /* staging in progress. look for new ACME account information collected there */
         rv = md_reg_creds_get(&ad->ncreds, d->reg, MD_SG_STAGING, d->md, d->p);
@@ -684,14 +712,14 @@ static apr_status_t acme_stage(md_proto_
     }
     
     /* Find out where we're at with this managed domain */
-    if (ad->ncreds && ad->ncreds->pkey && ad->ncreds->cert && ad->ncreds->chain) {
+    if (ad->ncreds && ad->ncreds->privkey && ad->ncreds->pubcert) {
         /* There is a full set staged, to be loaded */
         md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, d->p, "%s: all data staged", d->md->name);
         renew = 0;
     }
     
     if (renew) {
-        if (APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, d->md->ca_url)) 
+        if (APR_SUCCESS != (rv = md_acme_create(&ad->acme, d->p, d->md->ca_url, d->proxy_url)) 
             || APR_SUCCESS != (rv = md_acme_setup(ad->acme))) {
             md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p, "%s: setup ACME(%s)", 
                           d->md->name, d->md->ca_url);
@@ -724,11 +752,32 @@ static apr_status_t acme_stage(md_proto_
              * requests for new authorizations are denied. ToS may change during the
              * lifetime of an account */
             if (APR_SUCCESS == rv) {
+                const char *required;
+                
                 ad->phase = "check agreement";
                 md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, d->p, 
                               "%s: check Terms-of-Service agreement", d->md->name);
                 
-                rv = md_acme_check_agreement(ad->acme, d->p, ad->md->ca_agreement);
+                rv = md_acme_check_agreement(ad->acme, d->p, ad->md->ca_agreement, &required);
+                
+                if (APR_STATUS_IS_INCOMPLETE(rv) && required) {
+                    /* The CA wants the user to agree to Terms-of-Services. Until the user
+                     * has reconfigured and restarted the server, this MD cannot be
+                     * driven further */
+                    ad->md->state = MD_S_MISSING;
+                    md_save(d->store, d->p, MD_SG_STAGING, ad->md, 0);
+
+                    md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p, 
+                                  "%s: the CA requires you to accept the terms-of-service "
+                                  "as specified in <%s>. "
+                                  "Please read the document that you find at that URL and, "
+                                  "if you agree to the conditions, configure "
+                                  "\"MDCertificateAgreement url\" "
+                                  "with exactly that URL in your Apache. "
+                                  "Then (graceful) restart the server to activate.", 
+                                  ad->md->name, required);
+                    goto out;
+                }
             }
             
             /* If we know a cert's location, try to get it. Previous download might
@@ -780,11 +829,47 @@ static apr_status_t acme_stage(md_proto_
         }
         
         if (APR_SUCCESS == rv && !ad->chain) {
+            /* have we created this already? */
+            md_chain_load(d->store, MD_SG_STAGING, ad->md->name, &ad->chain, d->p);
+        }
+        if (APR_SUCCESS == rv && !ad->chain) {
             ad->phase = "install chain";
             md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, d->p, 
                           "%s: retrieving certificate chain", d->md->name);
             rv = ad_chain_install(d);
         }
+
+        if (APR_SUCCESS == rv && !ad->pubcert) {
+            /* have we created this already? */
+            md_pubcert_load(d->store, MD_SG_STAGING, ad->md->name, &ad->pubcert, d->p);
+        }
+        if (APR_SUCCESS == rv && !ad->pubcert) {
+            /* combine cert + chain into the pubcert */
+            ad->pubcert = apr_array_make(d->p, ad->chain->nelts + 1, sizeof(md_cert_t*));
+            APR_ARRAY_PUSH(ad->pubcert, md_cert_t *) = ad->cert;
+            apr_array_cat(ad->pubcert, ad->chain);
+            rv = md_pubcert_save(d->store, d->p, MD_SG_STAGING, ad->md->name, ad->pubcert, 0);
+        }
+
+        if (APR_SUCCESS == rv && ad->cert) {
+            apr_time_t now = apr_time_now();
+            apr_interval_time_t max_delay, delay_activation; 
+            
+            /* determine when this cert should be activated */
+            d->stage_valid_from = md_cert_get_not_before(ad->cert);
+            if (d->md->state == MD_S_COMPLETE && d->md->expires > now) {            
+                /**
+                 * The MD is complete and un-expired. This is a renewal run. 
+                 * Give activation 24 hours leeway (if we have that time) to
+                 * accomodate for clients with somewhat weird clocks.
+                 */
+                delay_activation = apr_time_from_sec(MD_SECS_PER_DAY);
+                if (delay_activation > (max_delay = d->md->expires - now)) {
+                    delay_activation = max_delay;
+                }
+                d->stage_valid_from += delay_activation;
+            }
+        }
     }
 out:    
     return rv;
@@ -809,13 +894,12 @@ static apr_status_t acme_driver_stage(md
 /* ACME preload */
 
 static apr_status_t acme_preload(md_store_t *store, md_store_group_t load_group, 
-                                 const char *name, apr_pool_t *p) 
+                                 const char *name, const char *proxy_url, apr_pool_t *p) 
 {
     apr_status_t rv;
-    md_pkey_t *pkey, *acct_key;
+    md_pkey_t *privkey, *acct_key;
     md_t *md;
-    md_cert_t *cert;
-    apr_array_header_t *chain;
+    apr_array_header_t *pubcert;
     struct md_acme_acct_t *acct;
 
     md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "%s: preload start", name);
@@ -832,16 +916,12 @@ static apr_status_t acme_preload(md_stor
         md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading md json", name);
         return rv;
     }
-    if (APR_SUCCESS != (rv = md_cert_load(store, MD_SG_STAGING, name, &cert, p))) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading certificate", name);
-        return rv;
-    }
-    if (APR_SUCCESS != (rv = md_chain_load(store, MD_SG_STAGING, name, &chain, p))) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading cert chain", name);
+    if (APR_SUCCESS != (rv = md_pkey_load(store, MD_SG_STAGING, name, &privkey, p))) {
+        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading staging private key", name);
         return rv;
     }
-    if (APR_SUCCESS != (rv = md_pkey_load(store, MD_SG_STAGING, name, &pkey, p))) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading staging private key", name);
+    if (APR_SUCCESS != (rv = md_pubcert_load(store, MD_SG_STAGING, name, &pubcert, p))) {
+        md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading pubcert", name);
         return rv;
     }
 
@@ -870,7 +950,7 @@ static apr_status_t acme_preload(md_stor
     if (acct) {
         md_acme_t *acme;
         
-        if (APR_SUCCESS != (rv = md_acme_create(&acme, p, md->ca_url))
+        if (APR_SUCCESS != (rv = md_acme_create(&acme, p, md->ca_url, proxy_url))
             || APR_SUCCESS != (rv = md_acme_acct_save(store, p, acme, acct, acct_key))) {
             md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: error saving acct", name);
             return rv;
@@ -884,16 +964,12 @@ static apr_status_t acme_preload(md_stor
         md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving md json", name);
         return rv;
     }
-    if (APR_SUCCESS != (rv = md_cert_save(store, p, load_group, name, cert, 1))) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving certificate", name);
-        return rv;
-    }
-    if (APR_SUCCESS != (rv = md_chain_save(store, p, load_group, name, chain, 1))) {
+    if (APR_SUCCESS != (rv = md_pubcert_save(store, p, load_group, name, pubcert, 1))) {
         md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving cert chain", name);
         return rv;
     }
-    if (APR_SUCCESS != (rv = md_pkey_save(store, p, load_group, name, pkey, 1))) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving domain private key", name);
+    if (APR_SUCCESS != (rv = md_pkey_save(store, p, load_group, name, privkey, 1))) {
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving private key", name);
         return rv;
     }
     
@@ -906,7 +982,7 @@ static apr_status_t acme_driver_preload(
     apr_status_t rv;
 
     ad->phase = "ACME preload";
-    if (APR_SUCCESS == (rv = acme_preload(d->store, group, d->md->name, d->p))) {
+    if (APR_SUCCESS == (rv = acme_preload(d->store, group, d->md->name, d->proxy_url, d->p))) {
         ad->phase = "preload done";
     }
         
@@ -921,6 +997,7 @@ static md_proto_t ACME_PROTO = {
  
 apr_status_t md_acme_protos_add(apr_hash_t *protos, apr_pool_t *p)
 {
+    (void)p;
     apr_hash_set(protos, MD_PROTO_ACME, sizeof(MD_PROTO_ACME)-1, &ACME_PROTO);
     return APR_SUCCESS;
 }

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_core.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_core.c?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_core.c (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_core.c Mon Nov 27 10:44:56 2017
@@ -24,6 +24,7 @@
 
 #include "md_json.h"
 #include "md.h"
+#include "md_crypt.h"
 #include "md_log.h"
 #include "md_store.h"
 #include "md_util.h"
@@ -84,6 +85,8 @@ md_t *md_create_empty(apr_pool_t *p)
         md->domains = apr_array_make(p, 5, sizeof(const char *));
         md->contacts = apr_array_make(p, 5, sizeof(const char *));
         md->drive_mode = MD_DRIVE_DEFAULT;
+        md->require_https = MD_REQUIRE_UNSET;
+        md->must_staple = -1;
         md->transitive = -1;
         md->defn_name = "unknown";
         md->defn_line_number = 0;
@@ -189,24 +192,43 @@ md_t *md_get_by_dns_overlap(struct apr_a
     return NULL;
 }
 
-const char *md_create(md_t **pmd, apr_pool_t *p, apr_array_header_t *domains)
+md_t *md_create(apr_pool_t *p, apr_array_header_t *domains)
 {
     md_t *md;
     
-    if (domains->nelts <= 0) {
-        return "needs at least one domain name";
-    }
-    
     md = md_create_empty(p);
-    if (!md) {
-        return "not enough memory";
-    }
-
     md->domains = md_array_str_compact(p, domains, 0);
     md->name = APR_ARRAY_IDX(md->domains, 0, const char *);
     
-    *pmd = md;
-    return NULL;   
+    return md;
+}
+
+int md_should_renew(const md_t *md) 
+{
+    apr_time_t now = apr_time_now();
+
+    if (md->expires <= now) {
+        return 1;
+    }
+    else if (md->expires > 0) {
+        double renew_win,  life;
+        apr_interval_time_t left;
+        
+        renew_win = (double)md->renew_window;
+        if (md->renew_norm > 0 
+            && md->renew_norm > renew_win
+            && md->expires > md->valid_from) {
+            /* Calc renewal days as fraction of cert lifetime - if known */
+            life = (double)(md->expires - md->valid_from); 
+            renew_win = life * renew_win / (double)md->renew_norm;
+        }
+        
+        left = md->expires - now;
+        if (left <= renew_win) {
+            return 1;
+        }                
+    }
+    return 0;
 }
 
 /**************************************************************************************************/
@@ -236,8 +258,12 @@ md_t *md_clone(apr_pool_t *p, const md_t
     if (md) {
         md->state = src->state;
         md->name = apr_pstrdup(p, src->name);
+        md->require_https = src->require_https;
+        md->must_staple = src->must_staple;
         md->drive_mode = src->drive_mode;
         md->domains = md_array_str_compact(p, src->domains, 0);
+        md->pkey_spec = src->pkey_spec;
+        md->renew_norm = src->renew_norm;
         md->renew_window = src->renew_window;
         md->contacts = md_array_str_clone(p, src->contacts);
         if (src->ca_url) md->ca_url = apr_pstrdup(p, src->ca_url);
@@ -254,6 +280,29 @@ md_t *md_clone(apr_pool_t *p, const md_t
     return md;   
 }
 
+md_t *md_merge(apr_pool_t *p, const md_t *add, const md_t *base)
+{
+    md_t *n = apr_pcalloc(p, sizeof(*n));
+
+    n->ca_url = add->ca_url? add->ca_url : base->ca_url;
+    n->ca_proto = add->ca_proto? add->ca_proto : base->ca_proto;
+    n->ca_agreement = add->ca_agreement? add->ca_agreement : base->ca_agreement;
+    n->require_https = (add->require_https != MD_REQUIRE_UNSET)? add->require_https : base->require_https;
+    n->must_staple = (add->must_staple >= 0)? add->must_staple : base->must_staple;
+    n->drive_mode = (add->drive_mode != MD_DRIVE_DEFAULT)? add->drive_mode : base->drive_mode;
+    n->pkey_spec = add->pkey_spec? add->pkey_spec : base->pkey_spec;
+    n->renew_norm = (add->renew_norm > 0)? add->renew_norm : base->renew_norm;
+    n->renew_window = (add->renew_window > 0)? add->renew_window : base->renew_window;
+    n->transitive = (add->transitive >= 0)? add->transitive : base->transitive;
+    if (add->ca_challenges) {
+        n->ca_challenges = apr_array_copy(p, add->ca_challenges);
+    }
+    else if (base->ca_challenges) {
+        n->ca_challenges = apr_array_copy(p, base->ca_challenges);
+    }
+    return n;
+}
+
 /**************************************************************************************************/
 /* format conversion */
 
@@ -273,6 +322,9 @@ md_json_t *md_to_json(const md_t *md, ap
         if (md->cert_url) {
             md_json_sets(md->cert_url, json, MD_KEY_CERT, MD_KEY_URL, NULL);
         }
+        if (md->pkey_spec) {
+            md_json_setj(md_pkey_spec_to_json(md->pkey_spec, p), json, MD_KEY_PKEY, NULL);
+        }
         md_json_setl(md->state, json, MD_KEY_STATE, NULL);
         md_json_setl(md->drive_mode, json, MD_KEY_DRIVE_MODE, NULL);
         if (md->expires > 0) {
@@ -280,12 +332,35 @@ md_json_t *md_to_json(const md_t *md, ap
             apr_rfc822_date(ts, md->expires);
             md_json_sets(ts, json, MD_KEY_CERT, MD_KEY_EXPIRES, NULL);
         }
-        md_json_setl(apr_time_sec(md->renew_window), json, MD_KEY_RENEW_WINDOW, NULL);
+        if (md->valid_from > 0) {
+            char *ts = apr_pcalloc(p, APR_RFC822_DATE_LEN);
+            apr_rfc822_date(ts, md->valid_from);
+            md_json_sets(ts, json, MD_KEY_CERT, MD_KEY_VALID_FROM, NULL);
+        }
+        if (md->renew_norm > 0) {
+            md_json_sets(apr_psprintf(p, "%ld%%", (long)(md->renew_window * 100L / md->renew_norm)), 
+                                      json, MD_KEY_RENEW_WINDOW, NULL);
+        }
+        else {
+            md_json_setl((long)apr_time_sec(md->renew_window), json, MD_KEY_RENEW_WINDOW, NULL);
+        }
+        md_json_setb(md_should_renew(md), json, MD_KEY_RENEW, NULL);
         if (md->ca_challenges && md->ca_challenges->nelts > 0) {
             apr_array_header_t *na;
             na = md_array_str_compact(p, md->ca_challenges, 0);
             md_json_setsa(na, json, MD_KEY_CA, MD_KEY_CHALLENGES, NULL);
         }
+        switch (md->require_https) {
+            case MD_REQUIRE_TEMPORARY:
+                md_json_sets(MD_KEY_TEMPORARY, json, MD_KEY_REQUIRE_HTTPS, NULL);
+                break;
+            case MD_REQUIRE_PERMANENT:
+                md_json_sets(MD_KEY_PERMANENT, json, MD_KEY_REQUIRE_HTTPS, NULL);
+                break;
+            default:
+                break;
+        }
+        md_json_setb(md->must_staple > 0, json, MD_KEY_MUST_STAPLE, NULL);
         return json;
     }
     return NULL;
@@ -304,7 +379,10 @@ md_t *md_from_json(md_json_t *json, apr_
         md->ca_url = md_json_dups(p, json, MD_KEY_CA, MD_KEY_URL, NULL);
         md->ca_agreement = md_json_dups(p, json, MD_KEY_CA, MD_KEY_AGREEMENT, NULL);
         md->cert_url = md_json_dups(p, json, MD_KEY_CERT, MD_KEY_URL, NULL);
-        md->state = (int)md_json_getl(json, MD_KEY_STATE, NULL);
+        if (md_json_has_key(json, MD_KEY_PKEY, MD_KEY_TYPE, NULL)) {
+            md->pkey_spec = md_pkey_spec_from_json(md_json_getj(json, MD_KEY_PKEY, NULL), p);
+        }
+        md->state = (md_state_t)md_json_getl(json, MD_KEY_STATE, NULL);
         md->drive_mode = (int)md_json_getl(json, MD_KEY_DRIVE_MODE, NULL);
         md->domains = md_array_str_compact(p, md->domains, 0);
         md->transitive = (int)md_json_getl(json, MD_KEY_TRANSITIVE, NULL);
@@ -312,11 +390,36 @@ md_t *md_from_json(md_json_t *json, apr_
         if (s && *s) {
             md->expires = apr_date_parse_rfc(s);
         }
+        s = md_json_dups(p, json, MD_KEY_CERT, MD_KEY_VALID_FROM, NULL);
+        if (s && *s) {
+            md->valid_from = apr_date_parse_rfc(s);
+        }
+        md->renew_norm = 0;
         md->renew_window = apr_time_from_sec(md_json_getl(json, MD_KEY_RENEW_WINDOW, NULL));
+        if (md->renew_window <= 0) {
+            s = md_json_gets(json, MD_KEY_RENEW_WINDOW, NULL);
+            if (s && strchr(s, '%')) {
+                int percent = atoi(s);
+                if (0 < percent && percent < 100) {
+                    md->renew_norm = apr_time_from_sec(100 * MD_SECS_PER_DAY);
+                    md->renew_window = apr_time_from_sec(percent * MD_SECS_PER_DAY);
+                }
+            }
+        }
         if (md_json_has_key(json, MD_KEY_CA, MD_KEY_CHALLENGES, NULL)) {
             md->ca_challenges = apr_array_make(p, 5, sizeof(const char*));
             md_json_dupsa(md->ca_challenges, p, json, MD_KEY_CA, MD_KEY_CHALLENGES, NULL);
         }
+        md->require_https = MD_REQUIRE_OFF;
+        s = md_json_gets(json, MD_KEY_REQUIRE_HTTPS, NULL);
+        if (s && !strcmp(MD_KEY_TEMPORARY, s)) {
+            md->require_https = MD_REQUIRE_TEMPORARY;
+        }
+        else if (s && !strcmp(MD_KEY_PERMANENT, s)) {
+            md->require_https = MD_REQUIRE_PERMANENT;
+        }
+        md->must_staple = (int)md_json_getb(json, MD_KEY_MUST_STAPLE, NULL);
+        
         return md;
     }
     return NULL;

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_crypt.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_crypt.c?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_crypt.c (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_crypt.c Mon Nov 27 10:44:56 2017
@@ -31,6 +31,7 @@
 
 #include "md.h"
 #include "md_crypt.h"
+#include "md_json.h"
 #include "md_log.h"
 #include "md_http.h"
 #include "md_util.h"
@@ -60,6 +61,8 @@ struct md_pkey_t {
 static void seed_RAND(int pid)
 {
     char seed[128];
+    
+    (void)pid;
     arc4random_buf(seed, sizeof(seed));
     RAND_seed(seed, sizeof(seed));
 }
@@ -83,7 +86,7 @@ static void seed_RAND(int pid)
 {   
     unsigned char stackdata[256];
     /* stolen from mod_ssl/ssl_engine_rand.c */
-    apr_size_t n, l;
+    int n;
     struct {
         time_t t;
         pid_t pid;
@@ -99,17 +102,11 @@ static void seed_RAND(int pid)
      */
     my_seed.pid = pid;
     
-    l = sizeof(my_seed);
-    RAND_seed((unsigned char *)&my_seed, l);
+    RAND_seed((unsigned char *)&my_seed, sizeof(my_seed));
     
     /*
      * seed in some current state of the run-time stack (128 bytes)
      */
-#if HAVE_VALGRIND && 0
-    if (ssl_running_on_valgrind) {
-        VALGRIND_MAKE_MEM_DEFINED(stackdata, sizeof(stackdata));
-    }
-#endif
     n = rand_choosenum(0, sizeof(stackdata)-128-1);
     RAND_seed(stackdata+n, 128);
 }
@@ -140,11 +137,13 @@ apr_status_t md_crypt_init(apr_pool_t *p
 typedef struct {
     char *data;
     apr_size_t len;
-} buffer;
+} buffer_rec;
 
 static apr_status_t fwrite_buffer(void *baton, apr_file_t *f, apr_pool_t *p) 
 {
-    buffer *buf = baton;
+    buffer_rec *buf = baton;
+    
+    (void)p;
     return apr_file_write_full(f, buf->data, buf->len, &buf->len);
 }
 
@@ -169,18 +168,146 @@ typedef struct {
 static int pem_passwd(char *buf, int size, int rwflag, void *baton)
 {
     passwd_ctx *ctx = baton;
+    
+    (void)rwflag;
     if (ctx->pass_len > 0) {
         if (ctx->pass_len < size) {
             size = (int)ctx->pass_len;
         }
-        memcpy(buf, ctx->pass_phrase, size);
+        memcpy(buf, ctx->pass_phrase, (size_t)size);
     }
     return ctx->pass_len;
 }
 
 /**************************************************************************************************/
+/* date time things */
+
+/* Get the apr time (micro seconds, since 1970) from an ASN1 time, as stored in X509
+ * certificates. OpenSSL now has a utility function, but other *SSL derivatives have
+ * not caughts up yet or chose to ignore. An alternative is implemented, we prefer 
+ * however the *SSL to maintain such things.
+ */
+static apr_time_t md_asn1_time_get(const ASN1_TIME* time)
+{
+#ifdef LIBRESSL_VERSION_NUMBER
+    /* courtesy: https://stackoverflow.com/questions/10975542/asn1-time-to-time-t-conversion#11263731
+     * all bugs are mine */
+    apr_time_exp_t t;
+    apr_time_t ts;
+    const char* str = (const char*) time->data;
+    apr_size_t i = 0;
+
+    memset(&t, 0, sizeof(t));
+
+    if (time->type == V_ASN1_UTCTIME) {/* two digit year */
+        t.tm_year = (str[i++] - '0') * 10;
+        t.tm_year += (str[i++] - '0');
+        if (t.tm_year < 70)
+            t.tm_year += 100;
+    } 
+    else if (time->type == V_ASN1_GENERALIZEDTIME) {/* four digit year */
+        t.tm_year = (str[i++] - '0') * 1000;
+        t.tm_year+= (str[i++] - '0') * 100;
+        t.tm_year+= (str[i++] - '0') * 10;
+        t.tm_year+= (str[i++] - '0');
+        t.tm_year -= 1900;
+    }
+    t.tm_mon  = (str[i++] - '0') * 10;
+    t.tm_mon += (str[i++] - '0') - 1; /* -1 since January is 0 not 1. */
+    t.tm_mday = (str[i++] - '0') * 10;
+    t.tm_mday+= (str[i++] - '0');
+    t.tm_hour = (str[i++] - '0') * 10;
+    t.tm_hour+= (str[i++] - '0');
+    t.tm_min  = (str[i++] - '0') * 10;
+    t.tm_min += (str[i++] - '0');
+    t.tm_sec  = (str[i++] - '0') * 10;
+    t.tm_sec += (str[i++] - '0');
+    
+    if (APR_SUCCESS == apr_time_exp_gmt_get(&ts, &t)) {
+        return ts;
+    }
+    return 0;
+#else 
+    int secs, days;
+    apr_time_t ts = apr_time_now();
+    
+    if (ASN1_TIME_diff(&days, &secs, NULL, time)) {
+        ts += apr_time_from_sec((days * MD_SECS_PER_DAY) + secs); 
+    }
+    return ts;
+#endif
+}
+
+
+/**************************************************************************************************/
 /* private keys */
 
+md_json_t *md_pkey_spec_to_json(const md_pkey_spec_t *spec, apr_pool_t *p)
+{
+    md_json_t *json = md_json_create(p);
+    if (json) {
+        switch (spec->type) {
+            case MD_PKEY_TYPE_DEFAULT:
+                md_json_sets("Default", json, MD_KEY_TYPE, NULL);
+                break;
+            case MD_PKEY_TYPE_RSA:
+                md_json_sets("RSA", json, MD_KEY_TYPE, NULL);
+                if (spec->params.rsa.bits >= MD_PKEY_RSA_BITS_MIN) {
+                    md_json_setl((long)spec->params.rsa.bits, json, MD_KEY_BITS, NULL);
+                }
+                break;
+            default:
+                md_json_sets("Unsupported", json, MD_KEY_TYPE, NULL);
+                break;
+        }
+    }
+    return json;    
+}
+
+md_pkey_spec_t *md_pkey_spec_from_json(struct md_json_t *json, apr_pool_t *p)
+{
+    md_pkey_spec_t *spec = apr_pcalloc(p, sizeof(*spec));
+    const char *s;
+    long l;
+    
+    if (spec) {
+        s = md_json_gets(json, MD_KEY_TYPE, NULL);
+        if (!s || !apr_strnatcasecmp("Default", s)) {
+            spec->type = MD_PKEY_TYPE_DEFAULT;
+        }
+        else if (!apr_strnatcasecmp("RSA", s)) {
+            spec->type = MD_PKEY_TYPE_RSA;
+            l = md_json_getl(json, MD_KEY_BITS, NULL);
+            if (l >= MD_PKEY_RSA_BITS_MIN) {
+                spec->params.rsa.bits = (unsigned int)l;
+            }
+            else {
+                spec->params.rsa.bits = MD_PKEY_RSA_BITS_DEF;
+            }
+        }
+    }
+    return spec;
+}
+
+int md_pkey_spec_eq(md_pkey_spec_t *spec1, md_pkey_spec_t *spec2)
+{
+    if (spec1 == spec2) {
+        return 1;
+    }
+    if (spec1 && spec2 && spec1->type == spec2->type) {
+        switch (spec1->type) {
+            case MD_PKEY_TYPE_DEFAULT:
+                return 1;
+            case MD_PKEY_TYPE_RSA:
+                if (spec1->params.rsa.bits == spec2->params.rsa.bits) {
+                    return 1;
+                }
+                break;
+        }
+    }
+    return 0;
+}
+
 static md_pkey_t *make_pkey(apr_pool_t *p) 
 {
     md_pkey_t *pkey = apr_pcalloc(p, sizeof(*pkey));
@@ -231,7 +358,7 @@ apr_status_t md_pkey_fload(md_pkey_t **p
             apr_pool_cleanup_register(p, pkey, pkey_cleanup, apr_pool_cleanup_null);
         }
         else {
-            long err = ERR_get_error();
+            unsigned long err = ERR_get_error();
             rv = APR_EINVAL;
             md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p, 
                           "error loading pkey %s: %s (pass phrase was %snull)", fname,
@@ -242,7 +369,7 @@ apr_status_t md_pkey_fload(md_pkey_t **p
     return rv;
 }
 
-static apr_status_t pkey_to_buffer(buffer *buffer, md_pkey_t *pkey, apr_pool_t *p,
+static apr_status_t pkey_to_buffer(buffer_rec *buffer, md_pkey_t *pkey, apr_pool_t *p,
                                    const char *pass, apr_size_t pass_len)
 {
     BIO *bio = BIO_new(BIO_s_mem());
@@ -251,6 +378,7 @@ static apr_status_t pkey_to_buffer(buffe
     void *cb_baton = NULL;
     passwd_ctx ctx;
     unsigned long err;
+    int i;
     
     if (!bio) {
         return APR_ENOMEM;
@@ -278,11 +406,12 @@ static apr_status_t pkey_to_buffer(buffe
         return APR_EINVAL;
     }
 
-    buffer->len = BIO_pending(bio);
-    if (buffer->len > 0) {
-        buffer->data = apr_palloc(p, buffer->len+1);
-        buffer->len = BIO_read(bio, buffer->data, (int)buffer->len);
-        buffer->data[buffer->len] = '\0';
+    i = BIO_pending(bio);
+    if (i > 0) {
+        buffer->data = apr_palloc(p, (apr_size_t)i + 1);
+        i = BIO_read(bio, buffer->data, i);
+        buffer->data[i] = '\0';
+        buffer->len = (apr_size_t)i;
     }
     BIO_free(bio);
     return APR_SUCCESS;
@@ -292,7 +421,7 @@ apr_status_t md_pkey_fsave(md_pkey_t *pk
                            const char *pass_phrase, apr_size_t pass_len,
                            const char *fname, apr_fileperms_t perms)
 {
-    buffer buffer;
+    buffer_rec buffer;
     apr_status_t rv;
     
     if (APR_SUCCESS == (rv = pkey_to_buffer(&buffer, pkey, p, pass_phrase, pass_len))) {
@@ -303,7 +432,7 @@ apr_status_t md_pkey_fsave(md_pkey_t *pk
     return rv;
 }
 
-apr_status_t md_pkey_gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, int bits)
+static apr_status_t gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, unsigned int bits)
 {
     EVP_PKEY_CTX *ctx = NULL;
     apr_status_t rv;
@@ -312,12 +441,12 @@ apr_status_t md_pkey_gen_rsa(md_pkey_t *
     ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
     if (ctx 
         && EVP_PKEY_keygen_init(ctx) >= 0
-        && EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) >= 0
+        && EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int)bits) >= 0
         && EVP_PKEY_keygen(ctx, &(*ppkey)->pkey) >= 0) {
         rv = APR_SUCCESS;
     }
     else {
-        md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, p, "unable to generate new key"); 
+        md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, p, "error generate pkey RSA %d", bits); 
         *ppkey = NULL;
         rv = APR_EGENERAL;
     }
@@ -328,7 +457,20 @@ apr_status_t md_pkey_gen_rsa(md_pkey_t *
     return rv;
 }
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+apr_status_t md_pkey_gen(md_pkey_t **ppkey, apr_pool_t *p, md_pkey_spec_t *spec)
+{
+    md_pkey_type_t ptype = spec? spec->type : MD_PKEY_TYPE_DEFAULT;
+    switch (ptype) {
+        case MD_PKEY_TYPE_DEFAULT:
+            return gen_rsa(ppkey, p, MD_PKEY_RSA_BITS_DEF);
+        case MD_PKEY_TYPE_RSA:
+            return gen_rsa(ppkey, p, spec->params.rsa.bits);
+        default:
+            return APR_ENOTIMPL;
+    }
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 
 #ifndef NID_tlsfeature
 #define NID_tlsfeature          1020
@@ -350,7 +492,7 @@ static void RSA_get0_key(const RSA *r,
 static const char *bn64(const BIGNUM *b, apr_pool_t *p) 
 {
     if (b) {
-         int len = BN_num_bytes(b);
+         apr_size_t len = (apr_size_t)BN_num_bytes(b);
          char *buffer = apr_pcalloc(p, len);
          if (buffer) {
             BN_bn2bin(b, (unsigned char *)buffer);
@@ -393,7 +535,7 @@ apr_status_t md_crypt_sign64(const char
     const char *sign64 = NULL;
     apr_status_t rv = APR_ENOMEM;
     
-    buffer = apr_pcalloc(p, EVP_PKEY_size(pkey->pkey));
+    buffer = apr_pcalloc(p, (apr_size_t)EVP_PKEY_size(pkey->pkey));
     if (buffer) {
         ctx = EVP_MD_CTX_create();
         if (ctx) {
@@ -508,7 +650,7 @@ apr_status_t md_crypt_sha256_digest_hex(
     unsigned char *buffer;
     size_t blen;
     apr_status_t rv;
-    int i;
+    unsigned int i;
     
     if (APR_SUCCESS == (rv = sha256_digest(&buffer, &blen, p, d, dlen))) {
         cp = dhex = apr_pcalloc(p,  2 * blen + 1);
@@ -577,14 +719,12 @@ int md_cert_has_expired(const md_cert_t
 
 apr_time_t md_cert_get_not_after(md_cert_t *cert)
 {
-    int secs, days;
-    apr_time_t time = apr_time_now();
-    ASN1_TIME *not_after = X509_get_notAfter(cert->x509);
-    
-    if (ASN1_TIME_diff(&days, &secs, NULL, not_after)) {
-        time += apr_time_from_sec((days * MD_SECS_PER_DAY) + secs); 
-    }
-    return time;
+    return md_asn1_time_get(X509_get_notAfter(cert->x509));
+}
+
+apr_time_t md_cert_get_not_before(md_cert_t *cert)
+{
+    return md_asn1_time_get(X509_get_notBefore(cert->x509));
 }
 
 int md_cert_covers_domain(md_cert_t *cert, const char *domain_name)
@@ -713,9 +853,10 @@ apr_status_t md_cert_fload(md_cert_t **p
     return rv;
 }
 
-static apr_status_t cert_to_buffer(buffer *buffer, md_cert_t *cert, apr_pool_t *p)
+static apr_status_t cert_to_buffer(buffer_rec *buffer, md_cert_t *cert, apr_pool_t *p)
 {
     BIO *bio = BIO_new(BIO_s_mem());
+    int i;
     
     if (!bio) {
         return APR_ENOMEM;
@@ -728,11 +869,12 @@ static apr_status_t cert_to_buffer(buffe
         return APR_EINVAL;
     }
 
-    buffer->len = BIO_pending(bio);
-    if (buffer->len > 0) {
-        buffer->data = apr_palloc(p, buffer->len+1);
-        buffer->len = BIO_read(bio, buffer->data, (int)buffer->len);
-        buffer->data[buffer->len] = '\0';
+    i = BIO_pending(bio);
+    if (i > 0) {
+        buffer->data = apr_palloc(p, (apr_size_t)i + 1);
+        i = BIO_read(bio, buffer->data, i);
+        buffer->data[i] = '\0';
+        buffer->len = (apr_size_t)i;
     }
     BIO_free(bio);
     return APR_SUCCESS;
@@ -741,7 +883,7 @@ static apr_status_t cert_to_buffer(buffe
 apr_status_t md_cert_fsave(md_cert_t *cert, apr_pool_t *p, 
                            const char *fname, apr_fileperms_t perms)
 {
-    buffer buffer;
+    buffer_rec buffer;
     apr_status_t rv;
     
     if (APR_SUCCESS == (rv = cert_to_buffer(&buffer, cert, p))) {
@@ -752,7 +894,7 @@ apr_status_t md_cert_fsave(md_cert_t *ce
 
 apr_status_t md_cert_to_base64url(const char **ps64, md_cert_t *cert, apr_pool_t *p)
 {
-    buffer buffer;
+    buffer_rec buffer;
     apr_status_t rv;
     
     if (APR_SUCCESS == (rv = cert_to_buffer(&buffer, cert, p))) {
@@ -785,7 +927,7 @@ apr_status_t md_cert_read_http(md_cert_t
             const unsigned char *bf = (const unsigned char*)der;
             X509 *x509;
             
-            if (NULL == (x509 = d2i_X509(NULL, &bf, der_len))) {
+            if (NULL == (x509 = d2i_X509(NULL, &bf, (long)der_len))) {
                 rv = APR_EINVAL;
             }
             else {
@@ -806,19 +948,16 @@ md_cert_state_t md_cert_state_get(md_cer
     return MD_CERT_UNKNOWN;
 }
 
-apr_status_t md_chain_fload(apr_array_header_t **pcerts, apr_pool_t *p, const char *fname)
+apr_status_t md_chain_fappend(struct apr_array_header_t *certs, apr_pool_t *p, const char *fname)
 {
     FILE *f;
     apr_status_t rv;
-    apr_array_header_t *certs = NULL;
     X509 *x509;
     md_cert_t *cert;
     unsigned long err;
     
     rv = md_util_fopen(&f, fname, "r");
     if (rv == APR_SUCCESS) {
-        certs = apr_array_make(p, 5, sizeof(md_cert_t *));
-        
         ERR_clear_error();
         while (NULL != (x509 = PEM_read_X509(f, NULL, NULL, NULL))) {
             cert = make_cert(p, x509);
@@ -850,6 +989,16 @@ apr_status_t md_chain_fload(apr_array_he
 out:
     md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, rv, p, "read chain file %s, found %d certs", 
                   fname, certs? certs->nelts : 0);
+    return rv;
+}
+
+apr_status_t md_chain_fload(apr_array_header_t **pcerts, apr_pool_t *p, const char *fname)
+{
+    apr_array_header_t *certs;
+    apr_status_t rv;
+
+    certs = apr_array_make(p, 5, sizeof(md_cert_t *));
+    rv = md_chain_fappend(certs, p, fname);
     *pcerts = (APR_SUCCESS == rv)? certs : NULL;
     return rv;
 }
@@ -863,6 +1012,7 @@ apr_status_t md_chain_fsave(apr_array_he
     unsigned long err = 0;
     int i;
     
+    (void)p;
     rv = md_util_fopen(&f, fname, "w");
     if (rv == APR_SUCCESS) {
         apr_file_perms_set(fname, perms);
@@ -889,11 +1039,6 @@ apr_status_t md_chain_fsave(apr_array_he
 /**************************************************************************************************/
 /* certificate signing requests */
 
-static const char *alt_name(const char *domain, apr_pool_t *p)
-{
-    return apr_psprintf(p, "DNS:%s", domain);
-}
-
 static const char *alt_names(apr_array_header_t *domains, apr_pool_t *p)
 {
     const char *alts = "", *sep = "", *domain;
@@ -949,9 +1094,19 @@ static apr_status_t add_must_staple(STAC
 {
     
     if (md->must_staple) {
-        X509_EXTENSION *x = X509V3_EXT_conf_nid(NULL, NULL, 
-                                                NID_tlsfeature, (char*)"DER:30:03:02:01:05");
+        X509_EXTENSION *x;
+        int nid;
+        
+        nid = OBJ_create("1.3.6.1.5.5.7.1.24", "OCSPReq", "OCSP Request");
+        if (NID_undef == nid) {
+            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, 
+                          "%s: unable to get NID for must-staple", md->name);
+            return APR_EGENERAL;
+        }
+        x = X509V3_EXT_conf_nid(NULL, NULL, nid, (char*)"DER:30:03:02:01:05");
         if (NULL == x) {
+            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, 
+                          "%s: unable to get x509 extension for must-staple", md->name);
             return APR_EGENERAL;
         }
         sk_X509_EXTENSION_push(exts, x);
@@ -1015,12 +1170,12 @@ apr_status_t md_cert_req_create(const ch
         md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: der length", md->name);
         rv = APR_EGENERAL; goto out;
     }
-    s = csr_der = apr_pcalloc(p, csr_der_len + 1);
+    s = csr_der = apr_pcalloc(p, (apr_size_t)csr_der_len + 1);
     if (i2d_X509_REQ(csr, (unsigned char**)&s) != csr_der_len) {
         md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: csr der enc", md->name);
         rv = APR_EGENERAL; goto out;
     }
-    csr_der_64 = md_util_base64url_encode(csr_der, csr_der_len, p);
+    csr_der_64 = md_util_base64url_encode(csr_der, (apr_size_t)csr_der_len, p);
     rv = APR_SUCCESS;
     
 out:
@@ -1038,7 +1193,7 @@ out:
 }
 
 apr_status_t md_cert_self_sign(md_cert_t **pcert, const char *cn, 
-                               const char *domain, md_pkey_t *pkey,
+                               apr_array_header_t *domains, md_pkey_t *pkey,
                                apr_interval_time_t valid_for, apr_pool_t *p)
 {
     X509 *x;
@@ -1050,49 +1205,55 @@ apr_status_t md_cert_self_sign(md_cert_t
     ASN1_INTEGER *asn1_rnd = NULL;
     unsigned char rnd[20];
     
-    assert(domain);
+    assert(domains);
     
     if (NULL == (x = X509_new()) 
         || NULL == (n = X509_NAME_new())) {
         rv = APR_ENOMEM;
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: openssl alloc X509 things", domain);
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: openssl alloc X509 things", cn);
         goto out; 
     }
     
     if (APR_SUCCESS != (rv = md_rand_bytes(rnd, sizeof(rnd), p))
         || !(big_rnd = BN_bin2bn(rnd, sizeof(rnd), NULL))
         || !(asn1_rnd = BN_to_ASN1_INTEGER(big_rnd, NULL))) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: setup random serial", domain);
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: setup random serial", cn);
         rv = APR_EGENERAL; goto out;
-    } 
+    }
+     
+    if (1 != X509_set_version(x, 2L)) {
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: setting x.509v3", cn);
+        rv = APR_EGENERAL; goto out;
+    }
+
     if (!X509_set_serialNumber(x, asn1_rnd)) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: set serial number", domain);
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: set serial number", cn);
         rv = APR_EGENERAL; goto out;
     }
     /* set common name and issue */
     if (!X509_NAME_add_entry_by_txt(n, "CN", MBSTRING_ASC, (const unsigned char*)cn, -1, -1, 0)
         || !X509_set_subject_name(x, n)
         || !X509_set_issuer_name(x, n)) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: name add entry", domain);
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "%s: name add entry", cn);
         rv = APR_EGENERAL; goto out;
     }
-    /* cert are uncontrained (but not very trustworthy) */
-    if (APR_SUCCESS != (rv = add_ext(x, NID_basic_constraints, "CA:TRUE, pathlen:0", p))) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set basic constraints ext", domain);
+    /* cert are unconstrained (but not very trustworthy) */
+    if (APR_SUCCESS != (rv = add_ext(x, NID_basic_constraints, "CA:FALSE, pathlen:0", p))) {
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set basic constraints ext", cn);
         goto out;
     }
     /* add the domain as alt name */
-    if (APR_SUCCESS != (rv = add_ext(x, NID_subject_alt_name, alt_name(domain, p), p))) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set alt_name ext", domain);
+    if (APR_SUCCESS != (rv = add_ext(x, NID_subject_alt_name, alt_names(domains, p), p))) {
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set alt_name ext", cn);
         goto out;
     }
     /* add our key */
     if (!X509_set_pubkey(x, pkey->pkey)) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set pkey in x509", domain);
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: set pkey in x509", cn);
         rv = APR_EGENERAL; goto out;
     }
     
-    days = ((apr_time_sec(valid_for) + MD_SECS_PER_DAY - 1)/ MD_SECS_PER_DAY);
+    days = (int)((apr_time_sec(valid_for) + MD_SECS_PER_DAY - 1)/ MD_SECS_PER_DAY);
     if (!X509_set_notBefore(x, ASN1_TIME_set(NULL, time(NULL)))) {
         rv = APR_EGENERAL; goto out;
     }
@@ -1102,7 +1263,7 @@ apr_status_t md_cert_self_sign(md_cert_t
 
     /* sign with same key */
     if (!X509_sign(x, pkey->pkey, EVP_sha256())) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: sign x509", domain);
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: sign x509", cn);
         rv = APR_EGENERAL; goto out;
     }
 

Modified: httpd/httpd/branches/2.4.x-mod_md/modules/md/md_crypt.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x-mod_md/modules/md/md_crypt.h?rev=1816423&r1=1804530&r2=1816423&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x-mod_md/modules/md/md_crypt.h (original)
+++ httpd/httpd/branches/2.4.x-mod_md/modules/md/md_crypt.h Mon Nov 27 10:44:56 2017
@@ -41,9 +41,25 @@ apr_status_t md_crypt_sha256_digest_hex(
 
 typedef struct md_pkey_t md_pkey_t;
 
+typedef enum {
+    MD_PKEY_TYPE_DEFAULT,
+    MD_PKEY_TYPE_RSA,
+} md_pkey_type_t;
+
+typedef struct md_pkey_rsa_spec_t {
+    apr_uint32_t bits;
+} md_pkey_rsa_spec_t;
+
+typedef struct md_pkey_spec_t {
+    md_pkey_type_t type;
+    union {
+        md_pkey_rsa_spec_t rsa;
+    } params;
+} md_pkey_spec_t;
+
 apr_status_t md_crypt_init(apr_pool_t *pool);
 
-apr_status_t md_pkey_gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, int bits);
+apr_status_t md_pkey_gen(md_pkey_t **ppkey, apr_pool_t *p, md_pkey_spec_t *spec);
 void md_pkey_free(md_pkey_t *pkey);
 
 const char *md_pkey_get_rsa_e64(md_pkey_t *pkey, apr_pool_t *p);
@@ -62,6 +78,10 @@ apr_status_t md_crypt_sign64(const char
 void *md_cert_get_X509(struct md_cert_t *cert);
 void *md_pkey_get_EVP_PKEY(struct md_pkey_t *pkey);
 
+struct md_json_t *md_pkey_spec_to_json(const md_pkey_spec_t *spec, apr_pool_t *p);
+md_pkey_spec_t *md_pkey_spec_from_json(struct md_json_t *json, apr_pool_t *p);
+int md_pkey_spec_eq(md_pkey_spec_t *spec1, md_pkey_spec_t *spec2);
+
 /**************************************************************************************************/
 /* X509 certificates */
 
@@ -88,6 +108,7 @@ int md_cert_has_expired(const md_cert_t
 int md_cert_covers_domain(md_cert_t *cert, const char *domain_name);
 int md_cert_covers_md(md_cert_t *cert, const struct md_t *md);
 apr_time_t md_cert_get_not_after(md_cert_t *cert);
+apr_time_t md_cert_get_not_before(md_cert_t *cert);
 
 apr_status_t md_cert_get_issuers_uri(const char **puri, md_cert_t *cert, apr_pool_t *p);
 apr_status_t md_cert_get_alt_names(apr_array_header_t **pnames, md_cert_t *cert, apr_pool_t *p);
@@ -99,12 +120,14 @@ apr_status_t md_chain_fload(struct apr_a
                             apr_pool_t *p, const char *fname);
 apr_status_t md_chain_fsave(struct apr_array_header_t *certs, 
                             apr_pool_t *p, const char *fname, apr_fileperms_t perms);
+apr_status_t md_chain_fappend(struct apr_array_header_t *certs, 
+                              apr_pool_t *p, const char *fname);
 
 apr_status_t md_cert_req_create(const char **pcsr_der_64, const struct md_t *md, 
                                 md_pkey_t *pkey, apr_pool_t *p);
 
 apr_status_t md_cert_self_sign(md_cert_t **pcert, const char *cn, 
-                               const char *domain, md_pkey_t *pkey,
+                               struct apr_array_header_t *domains, md_pkey_t *pkey,
                                apr_interval_time_t valid_for, apr_pool_t *p);
 
 #endif /* md_crypt_h */



Mime
View raw message