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 2021/11/24 11:07:53 UTC

svn commit: r1895289 [2/2] - in /httpd/httpd/branches/2.4.x: ./ changes-entries/ docs/manual/mod/ modules/md/

Modified: httpd/httpd/branches/2.4.x/modules/md/md_status.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_status.c?rev=1895289&r1=1895288&r2=1895289&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_status.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_status.c Wed Nov 24 11:07:53 2021
@@ -88,55 +88,88 @@ leave:
     return rv;
 }
 
-/**************************************************************************************************/
-/* md status information */
-
-static apr_status_t job_loadj(md_json_t **pjson, md_store_group_t group, const char *name, 
+static apr_status_t job_loadj(md_json_t **pjson, md_store_group_t group, const char *name,
                               struct md_reg_t *reg, int with_log, apr_pool_t *p)
 {
     apr_status_t rv;
-    
+
     md_store_t *store = md_reg_store_get(reg);
     rv = md_store_load_json(store, group, name, MD_FN_JOB, pjson, p);
     if (APR_SUCCESS == rv && !with_log) md_json_del(*pjson, MD_KEY_LOG, NULL);
     return rv;
 }
 
+static apr_status_t status_get_cert_json_ex(
+    md_json_t **pjson,
+    const md_cert_t *cert,
+    const md_t *md,
+    md_reg_t *reg,
+    md_ocsp_reg_t *ocsp,
+    int with_logs,
+    apr_pool_t *p)
+{
+    md_json_t *certj, *jobj;
+    md_timeperiod_t ocsp_valid;
+    md_ocsp_cert_stat_t cert_stat;
+    apr_status_t rv;
+
+    if (APR_SUCCESS != (rv = status_get_cert_json(&certj, cert, p))) goto leave;
+    if (md->stapling && ocsp) {
+        rv = md_ocsp_get_meta(&cert_stat, &ocsp_valid, ocsp, cert, p, md);
+        if (APR_SUCCESS == rv) {
+            md_json_sets(md_ocsp_cert_stat_name(cert_stat), certj, MD_KEY_OCSP, MD_KEY_STATUS, NULL);
+            md_json_set_timeperiod(&ocsp_valid, certj, MD_KEY_OCSP, MD_KEY_VALID, NULL);
+        }
+        else if (!APR_STATUS_IS_ENOENT(rv)) goto leave;
+        rv = APR_SUCCESS;
+        if (APR_SUCCESS == job_loadj(&jobj, MD_SG_OCSP, md->name, reg, with_logs, p)) {
+            md_json_setj(jobj, certj, MD_KEY_OCSP, MD_KEY_RENEWAL, NULL);
+        }
+    }
+leave:
+    *pjson = (APR_SUCCESS == rv)? certj : NULL;
+    return rv;
+}
+
+static int get_cert_count(const md_t *md, int from_staging)
+{
+    if (!from_staging && md->cert_files && md->cert_files->nelts) {
+        return md->cert_files->nelts;
+    }
+    return md_pkeys_spec_count(md->pks);
+}
+
+static const char *get_cert_name(const md_t *md, int i, int from_staging, apr_pool_t *p)
+{
+    if (!from_staging && md->cert_files && md->cert_files->nelts) {
+        /* static files configured, not from staging, used index names */
+        return apr_psprintf(p, "%d", i);
+    }
+    return md_pkey_spec_name(md_pkeys_spec_get(md->pks, i));
+}
+
 static apr_status_t status_get_certs_json(md_json_t **pjson, apr_array_header_t *certs,
+                                          int from_staging,
                                           const md_t *md, md_reg_t *reg,  
-                                          md_ocsp_reg_t *ocsp, int with_logs, 
+                                          md_ocsp_reg_t *ocsp, int with_logs,
                                           apr_pool_t *p)
 {
-    md_json_t *json, *certj, *jobj;
-    md_timeperiod_t certs_valid = {0, 0}, valid, ocsp_valid;
-    md_pkey_spec_t *spec;
+    md_json_t *json, *certj;
+    md_timeperiod_t certs_valid = {0, 0}, valid;
     md_cert_t *cert;
-    md_ocsp_cert_stat_t cert_stat;
     int i;
     apr_status_t rv = APR_SUCCESS;   
     
     json = md_json_create(p);
-    for (i = 0; i < md_cert_count(md); ++i) {
-        spec = md_pkeys_spec_get(md->pks, i);
+    for (i = 0; i < get_cert_count(md, from_staging); ++i) {
         cert = APR_ARRAY_IDX(certs, i, md_cert_t*);
         if (!cert) continue;
-        
-        if (APR_SUCCESS != (rv = status_get_cert_json(&certj, cert, p))) goto leave;
-        if (md->stapling && ocsp) {
-            rv = md_ocsp_get_meta(&cert_stat, &ocsp_valid, ocsp, cert, p, md);
-            if (APR_SUCCESS == rv) {
-                md_json_sets(md_ocsp_cert_stat_name(cert_stat), certj, MD_KEY_OCSP, MD_KEY_STATUS, NULL);
-                md_json_set_timeperiod(&ocsp_valid, certj, MD_KEY_OCSP, MD_KEY_VALID, NULL);
-            }
-            else if (!APR_STATUS_IS_ENOENT(rv)) goto leave;
-            rv = APR_SUCCESS;
-            if (APR_SUCCESS == job_loadj(&jobj, MD_SG_OCSP, md->name, reg, with_logs, p)) {
-                md_json_setj(jobj, certj, MD_KEY_OCSP, MD_KEY_RENEWAL, NULL);
-            }
-        }
+
+        rv = status_get_cert_json_ex(&certj, cert, md, reg, ocsp, with_logs, p);
+        if (APR_SUCCESS != rv) goto leave;
         valid = md_cert_get_valid(cert);
         certs_valid = i? md_timeperiod_common(&certs_valid, &valid) : valid;
-        md_json_setj(certj, json, md_pkey_spec_name(spec), NULL);
+        md_json_setj(certj, json, get_cert_name(md, i, from_staging, p), NULL);
     }
     
     if (certs_valid.start) {
@@ -157,7 +190,7 @@ static apr_status_t get_staging_certs_js
     apr_status_t rv;
     
     certs = apr_array_make(p, 5, sizeof(md_cert_t*));
-    for (i = 0; i < md_cert_count(md); ++i) {
+    for (i = 0; i < get_cert_count(md, 1); ++i) {
         spec = md_pkeys_spec_get(md->pks, i);
         cert = NULL;
         rv = md_pubcert_load(md_reg_store_get(reg), MD_SG_STAGING, md->name, spec, &chain, p);
@@ -166,7 +199,7 @@ static apr_status_t get_staging_certs_js
         }
         APR_ARRAY_PUSH(certs, const md_cert_t*) = cert;
     }
-    return status_get_certs_json(pjson, certs, md, reg, NULL, 0, p);
+    return status_get_certs_json(pjson, certs, 1, md, reg, NULL, 0, p);
 }
 
 static apr_status_t status_get_md_json(md_json_t **pjson, const md_t *md, 
@@ -182,9 +215,9 @@ static apr_status_t status_get_md_json(m
     apr_time_t renew_at;
     int i;
 
-    mdj = md_to_json(md, p);
+    mdj = md_to_public_json(md, p);
     certs = apr_array_make(p, 5, sizeof(md_cert_t*));
-    for (i = 0; i < md_cert_count(md); ++i) {
+    for (i = 0; i < get_cert_count(md, 0); ++i) {
         cert = NULL;
         if (APR_SUCCESS == md_reg_get_pubcert(&pubcert, reg, md, i, p)) {
             cert = APR_ARRAY_IDX(pubcert->certs, 0, const md_cert_t*);
@@ -192,7 +225,7 @@ static apr_status_t status_get_md_json(m
         APR_ARRAY_PUSH(certs, const md_cert_t*) = cert;
     }
     
-    rv = status_get_certs_json(&certsj, certs, md, reg, ocsp, with_logs, p);
+    rv = status_get_certs_json(&certsj, certs, 0, md, reg, ocsp, with_logs, p);
     if (APR_SUCCESS != rv) goto leave;
     md_json_setj(certsj, mdj, MD_KEY_CERT, NULL);
     
@@ -605,8 +638,9 @@ apr_status_t md_job_notify(md_job_t *job
     job->dirty = 1;
     if (APR_SUCCESS == rv && APR_SUCCESS == result->status) {
         job->notified = 1;
-        if (!strcmp("renewed", reason)) job->notified_renewed = 1;
-        job->error_runs = 0;
+        if (!strcmp("renewed", reason)) {
+            job->notified_renewed = 1;
+        }
     }
     else {
         ++job->error_runs;

Modified: httpd/httpd/branches/2.4.x/modules/md/md_store_fs.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_store_fs.c?rev=1895289&r1=1895288&r2=1895289&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_store_fs.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_store_fs.c Wed Nov 24 11:07:53 2021
@@ -631,7 +631,7 @@ static apr_status_t pfs_save(void *baton
         && MD_OK(mk_group_dir(&dir, s_fs, group, name, p))
         && MD_OK(md_util_path_merge(&fpath, ptemp, dir, aspect, NULL))) {
         
-        md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, 0, ptemp, "storing in %s", fpath);
+        md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, ptemp, "storing in %s", fpath);
         switch (vtype) {
             case MD_SV_TEXT:
                 rv = (create? md_text_fcreatex(fpath, perms->file, p, value)
@@ -745,7 +745,9 @@ static apr_status_t pfs_purge(void *bato
         /* Remove all files in dir, there should be no sub-dirs */
         rv = md_util_rm_recursive(dir, ptemp, 1);
     }
-    md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, rv, ptemp, "purge %s/%s (%s)", groupname, name, dir);
+    if (!APR_STATUS_IS_ENOENT(rv)) {
+        md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, rv, ptemp, "purge %s/%s (%s)", groupname, name, dir);
+    }
     return APR_SUCCESS;
 }
 
@@ -1018,12 +1020,12 @@ static apr_status_t pfs_move(void *baton
         }
         
         if (!MD_OK(apr_file_rename(to_dir, narch_dir, ptemp))) {
-                md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "rename from %s to %s", 
+                md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "rename from %s to %s",
                               to_dir, narch_dir);
                 goto out;
         }
         if (!MD_OK(apr_file_rename(from_dir, to_dir, ptemp))) {
-            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "rename from %s to %s", 
+            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "rename from %s to %s",
                           from_dir, to_dir);
             apr_file_rename(narch_dir, to_dir, ptemp);
             goto out;
@@ -1034,7 +1036,7 @@ static apr_status_t pfs_move(void *baton
     }
     else if (APR_STATUS_IS_ENOENT(rv)) {
         if (APR_SUCCESS != (rv = apr_file_rename(from_dir, to_dir, ptemp))) {
-            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "rename from %s to %s", 
+            md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "rename from %s to %s",
                           from_dir, to_dir);
             goto out;
         }
@@ -1075,8 +1077,9 @@ static apr_status_t pfs_rename(void *bat
         goto out;
     }
     
-    if (APR_SUCCESS != (rv = apr_file_rename(from_dir, to_dir, ptemp))) {
-        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "rename from %s to %s", 
+    if (APR_SUCCESS != (rv = apr_file_rename(from_dir, to_dir, ptemp))
+        && !APR_STATUS_IS_ENOENT(rv)) {
+        md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, ptemp, "rename from %s to %s",
                       from_dir, to_dir);
         goto out;
     }

Modified: httpd/httpd/branches/2.4.x/modules/md/md_version.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/md_version.h?rev=1895289&r1=1895288&r2=1895289&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/md_version.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/md_version.h Wed Nov 24 11:07:53 2021
@@ -27,7 +27,7 @@
  * @macro
  * Version number of the md module as c string
  */
-#define MOD_MD_VERSION "2.4.7"
+#define MOD_MD_VERSION "2.4.10"
 
 /**
  * @macro
@@ -35,7 +35,7 @@
  * release. This is a 24 bit number with 8 bits for major number, 8 bits
  * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
  */
-#define MOD_MD_VERSION_NUM 0x020407
+#define MOD_MD_VERSION_NUM 0x02040a
 
 #define MD_ACME_DEF_URL    "https://acme-v02.api.letsencrypt.org/directory"
 

Modified: httpd/httpd/branches/2.4.x/modules/md/mod_md.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/mod_md.c?rev=1895289&r1=1895288&r2=1895289&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/mod_md.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/mod_md.c Wed Nov 24 11:07:53 2021
@@ -54,7 +54,6 @@
 #include "mod_md_ocsp.h"
 #include "mod_md_os.h"
 #include "mod_md_status.h"
-#include "mod_ssl_openssl.h"
 
 static void md_hooks(apr_pool_t *pool);
 
@@ -324,11 +323,15 @@ static void merge_srv_config(md_t *md, m
         md->ca_agreement = md_config_gets(md->sc, MD_CONFIG_CA_AGREEMENT);
     }
     contact = md_config_gets(md->sc, MD_CONFIG_CA_CONTACT);
-    if (contact && contact[0]) {
+    if (md->contacts && md->contacts->nelts > 0) {
+        /* set explicitly */
+    }
+    else if (contact && contact[0]) {
         apr_array_clear(md->contacts);
         APR_ARRAY_PUSH(md->contacts, const char *) =
         md_util_schemify(p, contact, "mailto");
-    } else if( md->sc->s->server_admin && strcmp(DEFAULT_ADMIN, md->sc->s->server_admin)) {
+    }
+    else if( md->sc->s->server_admin && strcmp(DEFAULT_ADMIN, md->sc->s->server_admin)) {
         apr_array_clear(md->contacts);
         APR_ARRAY_PUSH(md->contacts, const char *) =
         md_util_schemify(p, md->sc->s->server_admin, "mailto");
@@ -350,6 +353,10 @@ static void merge_srv_config(md_t *md, m
     if (md->require_https < 0) {
         md->require_https = md_config_geti(md->sc, MD_CONFIG_REQUIRE_HTTPS);
     }
+    if (!md->ca_eab_kid) {
+        md->ca_eab_kid = md->sc->ca_eab_kid;
+        md->ca_eab_hmac = md->sc->ca_eab_hmac;
+    }
     if (md->must_staple < 0) {
         md->must_staple = md_config_geti(md->sc, MD_CONFIG_MUST_STAPLE);
     }
@@ -592,14 +599,18 @@ static apr_status_t link_md_to_servers(m
                              s->server_hostname, s->port, md->name, sc->name,
                              domain, (int)sc->assigned->nelts);
 
-                if (sc->ca_contact && sc->ca_contact[0]) {
+                if (md->contacts && md->contacts->nelts > 0) {
+                    /* set explicitly */
+                }
+                else if (sc->ca_contact && sc->ca_contact[0]) {
                     uri = md_util_schemify(p, sc->ca_contact, "mailto");
                     if (md_array_str_index(md->contacts, uri, 0, 0) < 0) {
                         APR_ARRAY_PUSH(md->contacts, const char *) = uri;
                         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, base_server, APLOGNO(10044)
                                      "%s: added contact %s", md->name, uri);
                     }
-                } else if (s->server_admin && strcmp(DEFAULT_ADMIN, s->server_admin)) {
+                }
+                else if (s->server_admin && strcmp(DEFAULT_ADMIN, s->server_admin)) {
                     uri = md_util_schemify(p, s->server_admin, "mailto");
                     if (md_array_str_index(md->contacts, uri, 0, 0) < 0) {
                         APR_ARRAY_PUSH(md->contacts, const char *) = uri;
@@ -675,18 +686,18 @@ static apr_status_t merge_mds_with_conf(
         if (md->cert_files && md->cert_files->nelts) {
             if (!md->pkey_files || (md->cert_files->nelts != md->pkey_files->nelts)) {
                 ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10170)
-                             "The Managed Domain '%s', defined in %s(line %d), "
+                             "The Managed Domain '%s' "
                              "needs one MDCertificateKeyFile for each MDCertificateFile.",
-                             md->name, md->defn_name, md->defn_line_number);
+                             md->name);
                 return APR_EINVAL;
             }
         }
         else if (md->pkey_files && md->pkey_files->nelts 
             && (!md->cert_files || !md->cert_files->nelts)) {
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, base_server, APLOGNO(10171)
-                         "The Managed Domain '%s', defined in %s(line %d), "
+                         "The Managed Domain '%s' "
                          "has MDCertificateKeyFile(s) but no MDCertificateFile.",
-                         md->name, md->defn_name, md->defn_line_number);
+                         md->name);
             return APR_EINVAL;
         }
 

Modified: httpd/httpd/branches/2.4.x/modules/md/mod_md_config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/mod_md_config.c?rev=1895289&r1=1895288&r2=1895289&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/mod_md_config.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/mod_md_config.c Wed Nov 24 11:07:53 2021
@@ -28,6 +28,7 @@
 #include "md.h"
 #include "md_crypt.h"
 #include "md_log.h"
+#include "md_json.h"
 #include "md_util.h"
 #include "mod_md_private.h"
 #include "mod_md_config.h"
@@ -110,6 +111,8 @@ static md_srv_conf_t defconf = {
     "ACME",                    /* ca protocol */
     NULL,                      /* ca agreemnent */
     NULL,                      /* ca challenges array */
+    NULL,                      /* ca eab kid */
+    NULL,                      /* ca eab hmac */
     0,                         /* stapling */
     1,                         /* staple others */
     NULL,                      /* currently defined md */
@@ -162,6 +165,8 @@ static void srv_conf_props_clear(md_srv_
     sc->ca_proto = NULL;
     sc->ca_agreement = NULL;
     sc->ca_challenges = NULL;
+    sc->ca_eab_kid = NULL;
+    sc->ca_eab_hmac = NULL;
     sc->stapling = DEF_VAL;
     sc->staple_others = DEF_VAL;
 }
@@ -180,6 +185,8 @@ static void srv_conf_props_copy(md_srv_c
     to->ca_proto = from->ca_proto;
     to->ca_agreement = from->ca_agreement;
     to->ca_challenges = from->ca_challenges;
+    to->ca_eab_kid = from->ca_eab_kid;
+    to->ca_eab_hmac = from->ca_eab_hmac;
     to->stapling = from->stapling;
     to->staple_others = from->staple_others;
 }
@@ -196,7 +203,14 @@ static void srv_conf_props_apply(md_t *m
     if (from->ca_url) md->ca_url = from->ca_url;
     if (from->ca_proto) md->ca_proto = from->ca_proto;
     if (from->ca_agreement) md->ca_agreement = from->ca_agreement;
+    if (from->ca_contact) {
+        apr_array_clear(md->contacts);
+        APR_ARRAY_PUSH(md->contacts, const char *) =
+            md_util_schemify(p, from->ca_contact, "mailto");
+    }
     if (from->ca_challenges) md->ca_challenges = apr_array_copy(p, from->ca_challenges);
+    if (from->ca_eab_kid) md->ca_eab_kid = from->ca_eab_kid;
+    if (from->ca_eab_hmac) md->ca_eab_hmac = from->ca_eab_hmac;
     if (from->stapling != DEF_VAL) md->stapling = from->stapling;
 }
 
@@ -238,6 +252,8 @@ static void *md_config_merge(apr_pool_t
     nsc->ca_agreement = add->ca_agreement? add->ca_agreement : base->ca_agreement;
     nsc->ca_challenges = (add->ca_challenges? apr_array_copy(pool, add->ca_challenges) 
                     : (base->ca_challenges? apr_array_copy(pool, base->ca_challenges) : NULL));
+    nsc->ca_eab_kid = add->ca_eab_kid? add->ca_eab_kid : base->ca_eab_kid;
+    nsc->ca_eab_hmac = add->ca_eab_hmac? add->ca_eab_hmac : base->ca_eab_hmac;
     nsc->stapling = (add->stapling != DEF_VAL)? add->stapling : base->stapling;
     nsc->staple_others = (add->staple_others != DEF_VAL)? add->staple_others : base->staple_others;
     nsc->current = NULL;
@@ -461,13 +477,16 @@ static const char *md_config_set_names(c
 static const char *md_config_set_ca(cmd_parms *cmd, void *dc, const char *value)
 {
     md_srv_conf_t *sc = md_config_get(cmd->server);
-    const char *err;
+    const char *err, *url;
 
     (void)dc;
     if ((err = md_conf_check_location(cmd, MD_LOC_ALL))) {
         return err;
     }
-    sc->ca_url = value;
+    if (APR_SUCCESS != md_get_ca_url_from_name(&url, cmd->pool, value)) {
+        return url;
+    }
+    sc->ca_url = url;
     return NULL;
 }
 
@@ -1009,9 +1028,69 @@ static const char *md_config_set_ca_cert
     return NULL;
 }
 
+static const char *md_config_set_eab(cmd_parms *cmd, void *dc,
+                                     const char *keyid, const char *hmac)
+{
+    md_srv_conf_t *sc = md_config_get(cmd->server);
+    const char *err;
+
+    (void)dc;
+    if ((err = md_conf_check_location(cmd, MD_LOC_ALL))) {
+        return err;
+    }
+    if (!hmac) {
+        if (!apr_strnatcasecmp("None", keyid)) {
+            keyid = "none";
+        }
+        else {
+            /* a JSON file keeping keyid and hmac */
+            const char *fpath;
+            apr_status_t rv;
+            md_json_t *json;
+
+            /* If only dumping the config, don't verify the file */
+            if (ap_state_query(AP_SQ_RUN_MODE) == AP_SQ_RM_CONFIG_DUMP) {
+                goto leave;
+            }
+
+            fpath = ap_server_root_relative(cmd->pool, keyid);
+            if (!fpath) {
+                return apr_pstrcat(cmd->pool, cmd->cmd->name,
+                                   ": Invalid file path ", keyid, NULL);
+            }
+            if (!md_file_exists(fpath, cmd->pool)) {
+                return apr_pstrcat(cmd->pool, cmd->cmd->name,
+                                   ": file not found: ", fpath, NULL);
+            }
+
+            rv = md_json_readf(&json, cmd->pool, fpath);
+            if (APR_SUCCESS != rv) {
+                return apr_pstrcat(cmd->pool, cmd->cmd->name,
+                                   ": error reading JSON file ", fpath, NULL);
+            }
+            keyid = md_json_gets(json, MD_KEY_KID, NULL);
+            if (!keyid || !*keyid) {
+                return apr_pstrcat(cmd->pool, cmd->cmd->name,
+                                   ": JSON does not contain '", MD_KEY_KID,
+                                   "' element in file ", fpath, NULL);
+            }
+            hmac = md_json_gets(json, MD_KEY_HMAC, NULL);
+            if (!hmac || !*hmac) {
+                return apr_pstrcat(cmd->pool, cmd->cmd->name,
+                                   ": JSON does not contain '", MD_KEY_HMAC,
+                                   "' element in file ", fpath, NULL);
+            }
+        }
+    }
+leave:
+    sc->ca_eab_kid = keyid;
+    sc->ca_eab_hmac = hmac;
+    return NULL;
+}
+
 const command_rec md_cmds[] = {
     AP_INIT_TAKE1("MDCertificateAuthority", md_config_set_ca, NULL, RSRC_CONF, 
-                  "URL of CA issuing the certificates"),
+                  "URL or known name of CA issuing the certificates"),
     AP_INIT_TAKE1("MDCertificateAgreement", md_config_set_agreement, NULL, RSRC_CONF, 
                   "either 'accepted' or the URL of CA Terms-of-Service agreement you accept"),
     AP_INIT_TAKE_ARGV("MDCAChallenges", md_config_set_cha_tyes, NULL, RSRC_CONF, 
@@ -1085,6 +1164,8 @@ const command_rec md_cmds[] = {
                   "How long to delay activation of new certificates"),
     AP_INIT_TAKE1("MDCACertificateFile", md_config_set_ca_certs, NULL, RSRC_CONF,
                   "Set the CA file to use for connections"),
+    AP_INIT_TAKE12("MDExternalAccountBinding", md_config_set_eab, NULL, RSRC_CONF,
+                  "Set the external account binding keyid and hmac values to use at CA"),
 
     AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL)
 };

Modified: httpd/httpd/branches/2.4.x/modules/md/mod_md_config.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/mod_md_config.h?rev=1895289&r1=1895288&r2=1895289&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/mod_md_config.h (original)
+++ httpd/httpd/branches/2.4.x/modules/md/mod_md_config.h Wed Nov 24 11:07:53 2021
@@ -91,7 +91,9 @@ typedef struct md_srv_conf_t {
     const char *ca_proto;              /* protocol used vs CA (e.g. ACME) */
     const char *ca_agreement;          /* accepted agreement uri between CA and user */ 
     struct apr_array_header_t *ca_challenges; /* challenge types configured */
-    
+    const char *ca_eab_kid;            /* != NULL, external account binding keyid */
+    const char *ca_eab_hmac;           /* != NULL, external account binding hmac */
+
     int stapling;                      /* OCSP stapling enabled */
     int staple_others;                 /* Provide OCSP stapling for non-MD certificates */
 

Modified: httpd/httpd/branches/2.4.x/modules/md/mod_md_status.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/modules/md/mod_md_status.c?rev=1895289&r1=1895288&r2=1895289&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/modules/md/mod_md_status.c (original)
+++ httpd/httpd/branches/2.4.x/modules/md/mod_md_status.c Wed Nov 24 11:07:53 2021
@@ -172,7 +172,10 @@ static void si_val_status(status_ctx *ct
     apr_time_t until;
     (void)info;
     switch (md_json_getl(mdj, info->key, NULL)) {
-        case MD_S_INCOMPLETE: s = "incomplete"; break;
+        case MD_S_INCOMPLETE:
+            s = md_json_gets(mdj, MD_KEY_STATE_DESCR, NULL);
+            s = s? apr_psprintf(ctx->p, "incomplete: %s", s) : "incomplete";
+            break;
         case MD_S_EXPIRED_DEPRECATED:
         case MD_S_COMPLETE:
             until = md_json_get_time(mdj, MD_KEY_CERT, MD_KEY_VALID, MD_KEY_UNTIL, NULL);
@@ -188,28 +191,11 @@ static void si_val_status(status_ctx *ct
 static void si_val_url(status_ctx *ctx, md_json_t *mdj, const status_info *info)
 {
     const char *url, *s;
-    apr_uri_t uri_parsed;
 
-    
     s = url = md_json_gets(mdj, info->key, NULL);
     if (!url) return;
-    if (!strcmp(LE_ACMEv2_PROD, url)) {
-        s = "Let's Encrypt";
-    }
-    else if (!strcmp(LE_ACMEv2_STAGING, url)) {
-        s = "Let's Encrypt (staging)";
-    }
-    else if (!strcmp(LE_ACMEv1_PROD, url)) {
-        s = "Let's Encrypt (v1)";
-    }
-    else if (!strcmp(LE_ACMEv1_STAGING, url)) {
-        s = "Let's Encrypt (v1,staging)";
-    }
-    else if (APR_SUCCESS == apr_uri_parse(ctx->p, url, &uri_parsed)) {
-        s = uri_parsed.hostname;
-        
-    }
-    apr_brigade_printf(ctx->bb, NULL, NULL, "<a href='%s'>%s</a>", 
+    s = md_get_ca_name_from_url(ctx->p, url);
+    apr_brigade_printf(ctx->bb, NULL, NULL, "<a href='%s'>%s</a>",
                        ap_escape_html2(ctx->p, url, 1), 
                        ap_escape_html2(ctx->p, s, 1));
 }
@@ -326,13 +312,24 @@ static void si_val_ca_url(status_ctx *ct
     jcert = md_json_getj(mdj, info->key, NULL);
     if (jcert) si_val_url(ctx, jcert, &sub);
 }
-    
+
+static int count_certs(void *baton, const char *key, md_json_t *json)
+{
+    int *pcount = baton;
+
+    (void)json;
+    if (strcmp(key, MD_KEY_VALID)) {
+        *pcount += 1;
+    }
+    return 1;
+}
+
 static void print_job_summary(apr_bucket_brigade *bb, md_json_t *mdj, const char *key, 
                               const char *separator)
 {
     char buffer[HUGE_STRING_LEN];
     apr_status_t rv;
-    int finished, errors;
+    int finished, errors, cert_count;
     apr_time_t t;
     const char *s, *line;
     
@@ -353,8 +350,16 @@ static void print_job_summary(apr_bucket
     }
     
     if (finished) {
-        line = apr_psprintf(bb->p, "%s finished successfully.", line);
-    } 
+        cert_count = 0;
+        md_json_iterkey(count_certs, &cert_count, mdj, key, MD_KEY_CERT, NULL);
+        if (cert_count > 0) {
+            line =apr_psprintf(bb->p, "%s  finished, %d new certificate%s staged.",
+                               line, cert_count, cert_count > 1? "s" : "");
+        }
+        else {
+            line = apr_psprintf(bb->p, "%s  finished successfully.", line);
+        }
+    }
     else {
         s = md_json_gets(mdj, key, MD_KEY_LAST, MD_KEY_DETAIL, NULL);
         if (s) line = apr_psprintf(bb->p, "%s %s", line, s);